diff options
author | Tim Angus <tim@ngus.net> | 2006-05-16 20:41:57 +0000 |
---|---|---|
committer | Tim Angus <tim@ngus.net> | 2006-05-16 20:41:57 +0000 |
commit | 5c0efda0ef811b2bafedb2b4f53b083a9b90e1b4 (patch) | |
tree | 972db3bf7fabe5293b383bb51fcb1aa74cc0e309 /src | |
parent | f68a49a146f20c7b6fc8e19dd1c4e6d58cf473e9 (diff) |
* Removal of bot code
* Refactored botlib parsing code into qcommon
Diffstat (limited to 'src')
94 files changed, 3843 insertions, 37696 deletions
diff --git a/src/botlib/aasfile.h b/src/botlib/aasfile.h deleted file mode 100644 index d788b690..00000000 --- a/src/botlib/aasfile.h +++ /dev/null @@ -1,268 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - - -//NOTE: int = default signed -// default long - -#define AASID (('S'<<24)+('A'<<16)+('A'<<8)+'E') -#define AASVERSION_OLD 4 -#define AASVERSION 5 - -//presence types -#define PRESENCE_NONE 1 -#define PRESENCE_NORMAL 2 -#define PRESENCE_CROUCH 4 - -//travel types -#define MAX_TRAVELTYPES 32 -#define TRAVEL_INVALID 1 //temporary not possible -#define TRAVEL_WALK 2 //walking -#define TRAVEL_CROUCH 3 //crouching -#define TRAVEL_BARRIERJUMP 4 //jumping onto a barrier -#define TRAVEL_JUMP 5 //jumping -#define TRAVEL_LADDER 6 //climbing a ladder -#define TRAVEL_WALKOFFLEDGE 7 //walking of a ledge -#define TRAVEL_SWIM 8 //swimming -#define TRAVEL_WATERJUMP 9 //jump out of the water -#define TRAVEL_TELEPORT 10 //teleportation -#define TRAVEL_ELEVATOR 11 //travel by elevator -#define TRAVEL_ROCKETJUMP 12 //rocket jumping required for travel -#define TRAVEL_BFGJUMP 13 //bfg jumping required for travel -#define TRAVEL_GRAPPLEHOOK 14 //grappling hook required for travel -#define TRAVEL_DOUBLEJUMP 15 //double jump -#define TRAVEL_RAMPJUMP 16 //ramp jump -#define TRAVEL_STRAFEJUMP 17 //strafe jump -#define TRAVEL_JUMPPAD 18 //jump pad -#define TRAVEL_FUNCBOB 19 //func bob - -//additional travel flags -#define TRAVELTYPE_MASK 0xFFFFFF -#define TRAVELFLAG_NOTTEAM1 (1 << 24) -#define TRAVELFLAG_NOTTEAM2 (2 << 24) - -//face flags -#define FACE_SOLID 1 //just solid at the other side -#define FACE_LADDER 2 //ladder -#define FACE_GROUND 4 //standing on ground when in this face -#define FACE_GAP 8 //gap in the ground -#define FACE_LIQUID 16 //face seperating two areas with liquid -#define FACE_LIQUIDSURFACE 32 //face seperating liquid and air -#define FACE_BRIDGE 64 //can walk over this face if bridge is closed - -//area contents -#define AREACONTENTS_WATER 1 -#define AREACONTENTS_LAVA 2 -#define AREACONTENTS_SLIME 4 -#define AREACONTENTS_CLUSTERPORTAL 8 -#define AREACONTENTS_TELEPORTAL 16 -#define AREACONTENTS_ROUTEPORTAL 32 -#define AREACONTENTS_TELEPORTER 64 -#define AREACONTENTS_JUMPPAD 128 -#define AREACONTENTS_DONOTENTER 256 -#define AREACONTENTS_VIEWPORTAL 512 -#define AREACONTENTS_MOVER 1024 -#define AREACONTENTS_NOTTEAM1 2048 -#define AREACONTENTS_NOTTEAM2 4096 -//number of model of the mover inside this area -#define AREACONTENTS_MODELNUMSHIFT 24 -#define AREACONTENTS_MAXMODELNUM 0xFF -#define AREACONTENTS_MODELNUM (AREACONTENTS_MAXMODELNUM << AREACONTENTS_MODELNUMSHIFT) - -//area flags -#define AREA_GROUNDED 1 //bot can stand on the ground -#define AREA_LADDER 2 //area contains one or more ladder faces -#define AREA_LIQUID 4 //area contains a liquid -#define AREA_DISABLED 8 //area is disabled for routing when set -#define AREA_BRIDGE 16 //area ontop of a bridge - -//aas file header lumps -#define AAS_LUMPS 14 -#define AASLUMP_BBOXES 0 -#define AASLUMP_VERTEXES 1 -#define AASLUMP_PLANES 2 -#define AASLUMP_EDGES 3 -#define AASLUMP_EDGEINDEX 4 -#define AASLUMP_FACES 5 -#define AASLUMP_FACEINDEX 6 -#define AASLUMP_AREAS 7 -#define AASLUMP_AREASETTINGS 8 -#define AASLUMP_REACHABILITY 9 -#define AASLUMP_NODES 10 -#define AASLUMP_PORTALS 11 -#define AASLUMP_PORTALINDEX 12 -#define AASLUMP_CLUSTERS 13 - -//========== bounding box ========= - -//bounding box -typedef struct aas_bbox_s -{ - int presencetype; - int flags; - vec3_t mins, maxs; -} aas_bbox_t; - -//============ settings =========== - -//reachability to another area -typedef struct aas_reachability_s -{ - int areanum; //number of the reachable area - int facenum; //number of the face towards the other area - int edgenum; //number of the edge towards the other area - vec3_t start; //start point of inter area movement - vec3_t end; //end point of inter area movement - int traveltype; //type of travel required to get to the area - unsigned short int traveltime;//travel time of the inter area movement -} aas_reachability_t; - -//area settings -typedef struct aas_areasettings_s -{ - //could also add all kind of statistic fields - int contents; //contents of the area - int areaflags; //several area flags - int presencetype; //how a bot can be present in this area - int cluster; //cluster the area belongs to, if negative it's a portal - int clusterareanum; //number of the area in the cluster - int numreachableareas; //number of reachable areas from this one - int firstreachablearea; //first reachable area in the reachable area index -} aas_areasettings_t; - -//cluster portal -typedef struct aas_portal_s -{ - int areanum; //area that is the actual portal - int frontcluster; //cluster at front of portal - int backcluster; //cluster at back of portal - int clusterareanum[2]; //number of the area in the front and back cluster -} aas_portal_t; - -//cluster portal index -typedef int aas_portalindex_t; - -//cluster -typedef struct aas_cluster_s -{ - int numareas; //number of areas in the cluster - int numreachabilityareas; //number of areas with reachabilities - int numportals; //number of cluster portals - int firstportal; //first cluster portal in the index -} aas_cluster_t; - -//============ 3d definition ============ - -typedef vec3_t aas_vertex_t; - -//just a plane in the third dimension -typedef struct aas_plane_s -{ - vec3_t normal; //normal vector of the plane - float dist; //distance of the plane (normal vector * distance = point in plane) - int type; -} aas_plane_t; - -//edge -typedef struct aas_edge_s -{ - int v[2]; //numbers of the vertexes of this edge -} aas_edge_t; - -//edge index, negative if vertexes are reversed -typedef int aas_edgeindex_t; - -//a face bounds an area, often it will also seperate two areas -typedef struct aas_face_s -{ - int planenum; //number of the plane this face is in - int faceflags; //face flags (no use to create face settings for just this field) - int numedges; //number of edges in the boundary of the face - int firstedge; //first edge in the edge index - int frontarea; //area at the front of this face - int backarea; //area at the back of this face -} aas_face_t; - -//face index, stores a negative index if backside of face -typedef int aas_faceindex_t; - -//area with a boundary of faces -typedef struct aas_area_s -{ - int areanum; //number of this area - //3d definition - int numfaces; //number of faces used for the boundary of the area - int firstface; //first face in the face index used for the boundary of the area - vec3_t mins; //mins of the area - vec3_t maxs; //maxs of the area - vec3_t center; //'center' of the area -} aas_area_t; - -//nodes of the bsp tree -typedef struct aas_node_s -{ - int planenum; - int children[2]; //child nodes of this node, or areas as leaves when negative - //when a child is zero it's a solid leaf -} aas_node_t; - -//=========== aas file =============== - -//header lump -typedef struct -{ - int fileofs; - int filelen; -} aas_lump_t; - -//aas file header -typedef struct aas_header_s -{ - int ident; - int version; - int bspchecksum; - //data entries - aas_lump_t lumps[AAS_LUMPS]; -} aas_header_t; - - -//====== additional information ====== -/* - -- when a node child is a solid leaf the node child number is zero -- two adjacent areas (sharing a plane at opposite sides) share a face - this face is a portal between the areas -- when an area uses a face from the faceindex with a positive index - then the face plane normal points into the area -- the face edges are stored counter clockwise using the edgeindex -- two adjacent convex areas (sharing a face) only share One face - this is a simple result of the areas being convex -- the areas can't have a mixture of ground and gap faces - other mixtures of faces in one area are allowed -- areas with the AREACONTENTS_CLUSTERPORTAL in the settings have - the cluster number set to the negative portal number -- edge zero is a dummy -- face zero is a dummy -- area zero is a dummy -- node zero is a dummy -*/ diff --git a/src/botlib/be_aas.h b/src/botlib/be_aas.h deleted file mode 100644 index e5056358..00000000 --- a/src/botlib/be_aas.h +++ /dev/null @@ -1,222 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// - -/***************************************************************************** - * name: be_aas.h - * - * desc: Area Awareness System, stuff exported to the AI - * - * $Archive: /source/code/botlib/be_aas.h $ - * - *****************************************************************************/ - -#ifndef MAX_STRINGFIELD -#define MAX_STRINGFIELD 80 -#endif - -//travel flags -#define TFL_INVALID 0x00000001 //traveling temporary not possible -#define TFL_WALK 0x00000002 //walking -#define TFL_CROUCH 0x00000004 //crouching -#define TFL_BARRIERJUMP 0x00000008 //jumping onto a barrier -#define TFL_JUMP 0x00000010 //jumping -#define TFL_LADDER 0x00000020 //climbing a ladder -#define TFL_WALKOFFLEDGE 0x00000080 //walking of a ledge -#define TFL_SWIM 0x00000100 //swimming -#define TFL_WATERJUMP 0x00000200 //jumping out of the water -#define TFL_TELEPORT 0x00000400 //teleporting -#define TFL_ELEVATOR 0x00000800 //elevator -#define TFL_ROCKETJUMP 0x00001000 //rocket jumping -#define TFL_BFGJUMP 0x00002000 //bfg jumping -#define TFL_GRAPPLEHOOK 0x00004000 //grappling hook -#define TFL_DOUBLEJUMP 0x00008000 //double jump -#define TFL_RAMPJUMP 0x00010000 //ramp jump -#define TFL_STRAFEJUMP 0x00020000 //strafe jump -#define TFL_JUMPPAD 0x00040000 //jump pad -#define TFL_AIR 0x00080000 //travel through air -#define TFL_WATER 0x00100000 //travel through water -#define TFL_SLIME 0x00200000 //travel through slime -#define TFL_LAVA 0x00400000 //travel through lava -#define TFL_DONOTENTER 0x00800000 //travel through donotenter area -#define TFL_FUNCBOB 0x01000000 //func bobbing -#define TFL_FLIGHT 0x02000000 //flight -#define TFL_BRIDGE 0x04000000 //move over a bridge -// -#define TFL_NOTTEAM1 0x08000000 //not team 1 -#define TFL_NOTTEAM2 0x10000000 //not team 2 - -//default travel flags -#define TFL_DEFAULT TFL_WALK|TFL_CROUCH|TFL_BARRIERJUMP|\ - TFL_JUMP|TFL_LADDER|\ - TFL_WALKOFFLEDGE|TFL_SWIM|TFL_WATERJUMP|\ - TFL_TELEPORT|TFL_ELEVATOR|\ - TFL_AIR|TFL_WATER|TFL_JUMPPAD|TFL_FUNCBOB - -typedef enum -{ - SOLID_NOT, // no interaction with other objects - SOLID_TRIGGER, // only touch when inside, after moving - SOLID_BBOX, // touch on edge - SOLID_BSP // bsp clip, touch on edge -} solid_t; - -//a trace is returned when a box is swept through the AAS world -typedef struct aas_trace_s -{ - qboolean startsolid; // if true, the initial point was in a solid area - float fraction; // time completed, 1.0 = didn't hit anything - vec3_t endpos; // final position - int ent; // entity blocking the trace - int lastarea; // last area the trace was in (zero if none) - int area; // area blocking the trace (zero if none) - int planenum; // number of the plane that was hit -} aas_trace_t; - -/* Defined in botlib.h - -//bsp_trace_t hit surface -typedef struct bsp_surface_s -{ - char name[16]; - int flags; - int value; -} bsp_surface_t; - -//a trace is returned when a box is swept through the BSP world -typedef struct bsp_trace_s -{ - qboolean allsolid; // if true, plane is not valid - qboolean startsolid; // if true, the initial point was in a solid area - float fraction; // time completed, 1.0 = didn't hit anything - vec3_t endpos; // final position - cplane_t plane; // surface normal at impact - float exp_dist; // expanded plane distance - int sidenum; // number of the brush side hit - bsp_surface_t surface; // hit surface - int contents; // contents on other side of surface hit - int ent; // number of entity hit -} bsp_trace_t; -// -*/ - -//entity info -typedef struct aas_entityinfo_s -{ - int valid; // true if updated this frame - int type; // entity type - int flags; // entity flags - float ltime; // local time - float update_time; // time between last and current update - int number; // number of the entity - vec3_t origin; // origin of the entity - vec3_t angles; // angles of the model - vec3_t old_origin; // for lerping - vec3_t lastvisorigin; // last visible origin - vec3_t mins; // bounding box minimums - vec3_t maxs; // bounding box maximums - int groundent; // ground entity - int solid; // solid type - int modelindex; // model used - int modelindex2; // weapons, CTF flags, etc - int frame; // model frame number - int event; // impulse events -- muzzle flashes, footsteps, etc - int eventParm; // even parameter - int powerups; // bit flags - int weapon; // determines weapon and flash model, etc - int legsAnim; // mask off ANIM_TOGGLEBIT - int torsoAnim; // mask off ANIM_TOGGLEBIT -} aas_entityinfo_t; - -// area info -typedef struct aas_areainfo_s -{ - int contents; - int flags; - int presencetype; - int cluster; - vec3_t mins; - vec3_t maxs; - vec3_t center; -} aas_areainfo_t; - -// client movement prediction stop events, stop as soon as: -#define SE_NONE 0 -#define SE_HITGROUND 1 // the ground is hit -#define SE_LEAVEGROUND 2 // there's no ground -#define SE_ENTERWATER 4 // water is entered -#define SE_ENTERSLIME 8 // slime is entered -#define SE_ENTERLAVA 16 // lava is entered -#define SE_HITGROUNDDAMAGE 32 // the ground is hit with damage -#define SE_GAP 64 // there's a gap -#define SE_TOUCHJUMPPAD 128 // touching a jump pad area -#define SE_TOUCHTELEPORTER 256 // touching teleporter -#define SE_ENTERAREA 512 // the given stoparea is entered -#define SE_HITGROUNDAREA 1024 // a ground face in the area is hit -#define SE_HITBOUNDINGBOX 2048 // hit the specified bounding box -#define SE_TOUCHCLUSTERPORTAL 4096 // touching a cluster portal - -typedef struct aas_clientmove_s -{ - vec3_t endpos; //position at the end of movement prediction - int endarea; //area at end of movement prediction - vec3_t velocity; //velocity at the end of movement prediction - aas_trace_t trace; //last trace - int presencetype; //presence type at end of movement prediction - int stopevent; //event that made the prediction stop - int endcontents; //contents at the end of movement prediction - float time; //time predicted ahead - int frames; //number of frames predicted ahead -} aas_clientmove_t; - -// alternate route goals -#define ALTROUTEGOAL_ALL 1 -#define ALTROUTEGOAL_CLUSTERPORTALS 2 -#define ALTROUTEGOAL_VIEWPORTALS 4 - -typedef struct aas_altroutegoal_s -{ - vec3_t origin; - int areanum; - unsigned short starttraveltime; - unsigned short goaltraveltime; - unsigned short extratraveltime; -} aas_altroutegoal_t; - -// route prediction stop events -#define RSE_NONE 0 -#define RSE_NOROUTE 1 //no route to goal -#define RSE_USETRAVELTYPE 2 //stop as soon as on of the given travel types is used -#define RSE_ENTERCONTENTS 4 //stop when entering the given contents -#define RSE_ENTERAREA 8 //stop when entering the given area - -typedef struct aas_predictroute_s -{ - vec3_t endpos; //position at the end of movement prediction - int endarea; //area at end of movement prediction - int stopevent; //event that made the prediction stop - int endcontents; //contents at the end of movement prediction - int endtravelflags; //end travel flags - int numareas; //number of areas predicted ahead - int time; //time predicted ahead (in hundreth of a sec) -} aas_predictroute_t; diff --git a/src/botlib/be_aas_bsp.h b/src/botlib/be_aas_bsp.h deleted file mode 100644 index b3c38ea8..00000000 --- a/src/botlib/be_aas_bsp.h +++ /dev/null @@ -1,90 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_aas_bsp.h - * - * desc: AAS - * - * $Archive: /source/code/botlib/be_aas_bsp.h $ - * - *****************************************************************************/ - -#ifdef AASINTERN -//loads the given BSP file -int AAS_LoadBSPFile(void); -//dump the loaded BSP data -void AAS_DumpBSPData(void); -//unlink the given entity from the bsp tree leaves -void AAS_UnlinkFromBSPLeaves(bsp_link_t *leaves); -//link the given entity to the bsp tree leaves of the given model -bsp_link_t *AAS_BSPLinkEntity(vec3_t absmins, - vec3_t absmaxs, - int entnum, - int modelnum); - -//calculates collision with given entity -qboolean AAS_EntityCollision(int entnum, - vec3_t start, - vec3_t boxmins, - vec3_t boxmaxs, - vec3_t end, - int contentmask, - bsp_trace_t *trace); -//for debugging -void AAS_PrintFreeBSPLinks(char *str); -// -#endif //AASINTERN - -#define MAX_EPAIRKEY 128 - -//trace through the world -bsp_trace_t AAS_Trace( vec3_t start, - vec3_t mins, - vec3_t maxs, - vec3_t end, - int passent, - int contentmask); -//returns the contents at the given point -int AAS_PointContents(vec3_t point); -//returns true when p2 is in the PVS of p1 -qboolean AAS_inPVS(vec3_t p1, vec3_t p2); -//returns true when p2 is in the PHS of p1 -qboolean AAS_inPHS(vec3_t p1, vec3_t p2); -//returns true if the given areas are connected -qboolean AAS_AreasConnected(int area1, int area2); -//creates a list with entities totally or partly within the given box -int AAS_BoxEntities(vec3_t absmins, vec3_t absmaxs, int *list, int maxcount); -//gets the mins, maxs and origin of a BSP model -void AAS_BSPModelMinsMaxsOrigin(int modelnum, vec3_t angles, vec3_t mins, vec3_t maxs, vec3_t origin); -//handle to the next bsp entity -int AAS_NextBSPEntity(int ent); -//return the value of the BSP epair key -int AAS_ValueForBSPEpairKey(int ent, char *key, char *value, int size); -//get a vector for the BSP epair key -int AAS_VectorForBSPEpairKey(int ent, char *key, vec3_t v); -//get a float for the BSP epair key -int AAS_FloatForBSPEpairKey(int ent, char *key, float *value); -//get an integer for the BSP epair key -int AAS_IntForBSPEpairKey(int ent, char *key, int *value); - diff --git a/src/botlib/be_aas_bspq3.c b/src/botlib/be_aas_bspq3.c deleted file mode 100644 index a920d641..00000000 --- a/src/botlib/be_aas_bspq3.c +++ /dev/null @@ -1,488 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_aas_bspq3.c - * - * desc: BSP, Environment Sampling - * - * $Archive: /MissionPack/code/botlib/be_aas_bspq3.c $ - * - *****************************************************************************/ - -#include "../qcommon/q_shared.h" -#include "l_memory.h" -#include "l_script.h" -#include "l_precomp.h" -#include "l_struct.h" -#include "aasfile.h" -#include "botlib.h" -#include "be_aas.h" -#include "be_aas_funcs.h" -#include "be_aas_def.h" - -extern botlib_import_t botimport; - -//#define TRACE_DEBUG - -#define ON_EPSILON 0.005 -//#define DEG2RAD( a ) (( a * M_PI ) / 180.0F) - -#define MAX_BSPENTITIES 2048 - -typedef struct rgb_s -{ - int red; - int green; - int blue; -} rgb_t; - -//bsp entity epair -typedef struct bsp_epair_s -{ - char *key; - char *value; - struct bsp_epair_s *next; -} bsp_epair_t; - -//bsp data entity -typedef struct bsp_entity_s -{ - bsp_epair_t *epairs; -} bsp_entity_t; - -//id Sofware BSP data -typedef struct bsp_s -{ - //true when bsp file is loaded - int loaded; - //entity data - int entdatasize; - char *dentdata; - //bsp entities - int numentities; - bsp_entity_t entities[MAX_BSPENTITIES]; -} bsp_t; - -//global bsp -bsp_t bspworld; - - -#ifdef BSP_DEBUG -typedef struct cname_s -{ - int value; - char *name; -} cname_t; - -cname_t contentnames[] = -{ - {CONTENTS_SOLID,"CONTENTS_SOLID"}, - {CONTENTS_WINDOW,"CONTENTS_WINDOW"}, - {CONTENTS_AUX,"CONTENTS_AUX"}, - {CONTENTS_LAVA,"CONTENTS_LAVA"}, - {CONTENTS_SLIME,"CONTENTS_SLIME"}, - {CONTENTS_WATER,"CONTENTS_WATER"}, - {CONTENTS_MIST,"CONTENTS_MIST"}, - {LAST_VISIBLE_CONTENTS,"LAST_VISIBLE_CONTENTS"}, - - {CONTENTS_AREAPORTAL,"CONTENTS_AREAPORTAL"}, - {CONTENTS_PLAYERCLIP,"CONTENTS_PLAYERCLIP"}, - {CONTENTS_MONSTERCLIP,"CONTENTS_MONSTERCLIP"}, - {CONTENTS_CURRENT_0,"CONTENTS_CURRENT_0"}, - {CONTENTS_CURRENT_90,"CONTENTS_CURRENT_90"}, - {CONTENTS_CURRENT_180,"CONTENTS_CURRENT_180"}, - {CONTENTS_CURRENT_270,"CONTENTS_CURRENT_270"}, - {CONTENTS_CURRENT_UP,"CONTENTS_CURRENT_UP"}, - {CONTENTS_CURRENT_DOWN,"CONTENTS_CURRENT_DOWN"}, - {CONTENTS_ORIGIN,"CONTENTS_ORIGIN"}, - {CONTENTS_MONSTER,"CONTENTS_MONSTER"}, - {CONTENTS_DEADMONSTER,"CONTENTS_DEADMONSTER"}, - {CONTENTS_DETAIL,"CONTENTS_DETAIL"}, - {CONTENTS_TRANSLUCENT,"CONTENTS_TRANSLUCENT"}, - {CONTENTS_LADDER,"CONTENTS_LADDER"}, - {0, 0} -}; - -void PrintContents(int contents) -{ - int i; - - for (i = 0; contentnames[i].value; i++) - { - if (contents & contentnames[i].value) - { - botimport.Print(PRT_MESSAGE, "%s\n", contentnames[i].name); - } //end if - } //end for -} //end of the function PrintContents - -#endif // BSP_DEBUG -//=========================================================================== -// traces axial boxes of any size through the world -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bsp_trace_t AAS_Trace(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int passent, int contentmask) -{ - bsp_trace_t bsptrace; - botimport.Trace(&bsptrace, start, mins, maxs, end, passent, contentmask); - return bsptrace; -} //end of the function AAS_Trace -//=========================================================================== -// returns the contents at the given point -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_PointContents(vec3_t point) -{ - return botimport.PointContents(point); -} //end of the function AAS_PointContents -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -qboolean AAS_EntityCollision(int entnum, - vec3_t start, vec3_t boxmins, vec3_t boxmaxs, vec3_t end, - int contentmask, bsp_trace_t *trace) -{ - bsp_trace_t enttrace; - - botimport.EntityTrace(&enttrace, start, boxmins, boxmaxs, end, entnum, contentmask); - if (enttrace.fraction < trace->fraction) - { - Com_Memcpy(trace, &enttrace, sizeof(bsp_trace_t)); - return qtrue; - } //end if - return qfalse; -} //end of the function AAS_EntityCollision -//=========================================================================== -// returns true if in Potentially Hearable Set -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -qboolean AAS_inPVS(vec3_t p1, vec3_t p2) -{ - return botimport.inPVS(p1, p2); -} //end of the function AAS_InPVS -//=========================================================================== -// returns true if in Potentially Visible Set -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -qboolean AAS_inPHS(vec3_t p1, vec3_t p2) -{ - return qtrue; -} //end of the function AAS_inPHS -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_BSPModelMinsMaxsOrigin(int modelnum, vec3_t angles, vec3_t mins, vec3_t maxs, vec3_t origin) -{ - botimport.BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, origin); -} //end of the function AAS_BSPModelMinsMaxs -//=========================================================================== -// unlinks the entity from all leaves -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_UnlinkFromBSPLeaves(bsp_link_t *leaves) -{ -} //end of the function AAS_UnlinkFromBSPLeaves -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bsp_link_t *AAS_BSPLinkEntity(vec3_t absmins, vec3_t absmaxs, int entnum, int modelnum) -{ - return NULL; -} //end of the function AAS_BSPLinkEntity -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_BoxEntities(vec3_t absmins, vec3_t absmaxs, int *list, int maxcount) -{ - return 0; -} //end of the function AAS_BoxEntities -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_NextBSPEntity(int ent) -{ - ent++; - if (ent >= 1 && ent < bspworld.numentities) return ent; - return 0; -} //end of the function AAS_NextBSPEntity -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_BSPEntityInRange(int ent) -{ - if (ent <= 0 || ent >= bspworld.numentities) - { - botimport.Print(PRT_MESSAGE, "bsp entity out of range\n"); - return qfalse; - } //end if - return qtrue; -} //end of the function AAS_BSPEntityInRange -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_ValueForBSPEpairKey(int ent, char *key, char *value, int size) -{ - bsp_epair_t *epair; - - value[0] = '\0'; - if (!AAS_BSPEntityInRange(ent)) return qfalse; - for (epair = bspworld.entities[ent].epairs; epair; epair = epair->next) - { - if (!strcmp(epair->key, key)) - { - strncpy(value, epair->value, size-1); - value[size-1] = '\0'; - return qtrue; - } //end if - } //end for - return qfalse; -} //end of the function AAS_FindBSPEpair -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_VectorForBSPEpairKey(int ent, char *key, vec3_t v) -{ - char buf[MAX_EPAIRKEY]; - double v1, v2, v3; - - VectorClear(v); - if (!AAS_ValueForBSPEpairKey(ent, key, buf, MAX_EPAIRKEY)) return qfalse; - //scanf into doubles, then assign, so it is vec_t size independent - v1 = v2 = v3 = 0; - sscanf(buf, "%lf %lf %lf", &v1, &v2, &v3); - v[0] = v1; - v[1] = v2; - v[2] = v3; - return qtrue; -} //end of the function AAS_VectorForBSPEpairKey -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_FloatForBSPEpairKey(int ent, char *key, float *value) -{ - char buf[MAX_EPAIRKEY]; - - *value = 0; - if (!AAS_ValueForBSPEpairKey(ent, key, buf, MAX_EPAIRKEY)) return qfalse; - *value = atof(buf); - return qtrue; -} //end of the function AAS_FloatForBSPEpairKey -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_IntForBSPEpairKey(int ent, char *key, int *value) -{ - char buf[MAX_EPAIRKEY]; - - *value = 0; - if (!AAS_ValueForBSPEpairKey(ent, key, buf, MAX_EPAIRKEY)) return qfalse; - *value = atoi(buf); - return qtrue; -} //end of the function AAS_IntForBSPEpairKey -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_FreeBSPEntities(void) -{ - int i; - bsp_entity_t *ent; - bsp_epair_t *epair, *nextepair; - - for (i = 1; i < bspworld.numentities; i++) - { - ent = &bspworld.entities[i]; - for (epair = ent->epairs; epair; epair = nextepair) - { - nextepair = epair->next; - // - if (epair->key) FreeMemory(epair->key); - if (epair->value) FreeMemory(epair->value); - FreeMemory(epair); - } //end for - } //end for - bspworld.numentities = 0; -} //end of the function AAS_FreeBSPEntities -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_ParseBSPEntities(void) -{ - script_t *script; - token_t token; - bsp_entity_t *ent; - bsp_epair_t *epair; - - script = LoadScriptMemory(bspworld.dentdata, bspworld.entdatasize, "entdata"); - SetScriptFlags(script, SCFL_NOSTRINGWHITESPACES|SCFL_NOSTRINGESCAPECHARS);//SCFL_PRIMITIVE); - - bspworld.numentities = 1; - - while(PS_ReadToken(script, &token)) - { - if (strcmp(token.string, "{")) - { - ScriptError(script, "invalid %s\n", token.string); - AAS_FreeBSPEntities(); - FreeScript(script); - return; - } //end if - if (bspworld.numentities >= MAX_BSPENTITIES) - { - botimport.Print(PRT_MESSAGE, "too many entities in BSP file\n"); - break; - } //end if - ent = &bspworld.entities[bspworld.numentities]; - bspworld.numentities++; - ent->epairs = NULL; - while(PS_ReadToken(script, &token)) - { - if (!strcmp(token.string, "}")) break; - epair = (bsp_epair_t *) GetClearedHunkMemory(sizeof(bsp_epair_t)); - epair->next = ent->epairs; - ent->epairs = epair; - if (token.type != TT_STRING) - { - ScriptError(script, "invalid %s\n", token.string); - AAS_FreeBSPEntities(); - FreeScript(script); - return; - } //end if - StripDoubleQuotes(token.string); - epair->key = (char *) GetHunkMemory(strlen(token.string) + 1); - strcpy(epair->key, token.string); - if (!PS_ExpectTokenType(script, TT_STRING, 0, &token)) - { - AAS_FreeBSPEntities(); - FreeScript(script); - return; - } //end if - StripDoubleQuotes(token.string); - epair->value = (char *) GetHunkMemory(strlen(token.string) + 1); - strcpy(epair->value, token.string); - } //end while - if (strcmp(token.string, "}")) - { - ScriptError(script, "missing }\n"); - AAS_FreeBSPEntities(); - FreeScript(script); - return; - } //end if - } //end while - FreeScript(script); -} //end of the function AAS_ParseBSPEntities -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_BSPTraceLight(vec3_t start, vec3_t end, vec3_t endpos, int *red, int *green, int *blue) -{ - return 0; -} //end of the function AAS_BSPTraceLight -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_DumpBSPData(void) -{ - AAS_FreeBSPEntities(); - - if (bspworld.dentdata) FreeMemory(bspworld.dentdata); - bspworld.dentdata = NULL; - bspworld.entdatasize = 0; - // - bspworld.loaded = qfalse; - Com_Memset( &bspworld, 0, sizeof(bspworld) ); -} //end of the function AAS_DumpBSPData -//=========================================================================== -// load an bsp file -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_LoadBSPFile(void) -{ - AAS_DumpBSPData(); - bspworld.entdatasize = strlen(botimport.BSPEntityData()) + 1; - bspworld.dentdata = (char *) GetClearedHunkMemory(bspworld.entdatasize); - Com_Memcpy(bspworld.dentdata, botimport.BSPEntityData(), bspworld.entdatasize); - AAS_ParseBSPEntities(); - bspworld.loaded = qtrue; - return BLERR_NOERROR; -} //end of the function AAS_LoadBSPFile diff --git a/src/botlib/be_aas_cluster.c b/src/botlib/be_aas_cluster.c deleted file mode 100644 index 2805dc99..00000000 --- a/src/botlib/be_aas_cluster.c +++ /dev/null @@ -1,1546 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_aas_cluster.c - * - * desc: area clustering - * - * $Archive: /MissionPack/code/botlib/be_aas_cluster.c $ - * - *****************************************************************************/ - -#include "../qcommon/q_shared.h" -#include "l_memory.h" -#include "l_script.h" -#include "l_precomp.h" -#include "l_struct.h" -#include "l_log.h" -#include "l_memory.h" -#include "l_libvar.h" -#include "aasfile.h" -#include "botlib.h" -#include "be_aas.h" -#include "be_aas_funcs.h" -#include "be_aas_def.h" - -extern botlib_import_t botimport; - -#define AAS_MAX_PORTALS 65536 -#define AAS_MAX_PORTALINDEXSIZE 65536 -#define AAS_MAX_CLUSTERS 65536 -// -#define MAX_PORTALAREAS 1024 - -// do not flood through area faces, only use reachabilities -int nofaceflood = qtrue; - -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_RemoveClusterAreas(void) -{ - int i; - - for (i = 1; i < aasworld.numareas; i++) - { - aasworld.areasettings[i].cluster = 0; - } //end for -} //end of the function AAS_RemoveClusterAreas -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_ClearCluster(int clusternum) -{ - int i; - - for (i = 1; i < aasworld.numareas; i++) - { - if (aasworld.areasettings[i].cluster == clusternum) - { - aasworld.areasettings[i].cluster = 0; - } //end if - } //end for -} //end of the function AAS_ClearCluster -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_RemovePortalsClusterReference(int clusternum) -{ - int portalnum; - - for (portalnum = 1; portalnum < aasworld.numportals; portalnum++) - { - if (aasworld.portals[portalnum].frontcluster == clusternum) - { - aasworld.portals[portalnum].frontcluster = 0; - } //end if - if (aasworld.portals[portalnum].backcluster == clusternum) - { - aasworld.portals[portalnum].backcluster = 0; - } //end if - } //end for -} //end of the function AAS_RemovePortalsClusterReference -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_UpdatePortal(int areanum, int clusternum) -{ - int portalnum; - aas_portal_t *portal; - aas_cluster_t *cluster; - - //find the portal of the area - for (portalnum = 1; portalnum < aasworld.numportals; portalnum++) - { - if (aasworld.portals[portalnum].areanum == areanum) break; - } //end for - // - if (portalnum == aasworld.numportals) - { - AAS_Error("no portal of area %d", areanum); - return qtrue; - } //end if - // - portal = &aasworld.portals[portalnum]; - //if the portal is already fully updated - if (portal->frontcluster == clusternum) return qtrue; - if (portal->backcluster == clusternum) return qtrue; - //if the portal has no front cluster yet - if (!portal->frontcluster) - { - portal->frontcluster = clusternum; - } //end if - //if the portal has no back cluster yet - else if (!portal->backcluster) - { - portal->backcluster = clusternum; - } //end else if - else - { - //remove the cluster portal flag contents - aasworld.areasettings[areanum].contents &= ~AREACONTENTS_CLUSTERPORTAL; - Log_Write("portal area %d is seperating more than two clusters\r\n", areanum); - return qfalse; - } //end else - if (aasworld.portalindexsize >= AAS_MAX_PORTALINDEXSIZE) - { - AAS_Error("AAS_MAX_PORTALINDEXSIZE"); - return qtrue; - } //end if - //set the area cluster number to the negative portal number - aasworld.areasettings[areanum].cluster = -portalnum; - //add the portal to the cluster using the portal index - cluster = &aasworld.clusters[clusternum]; - aasworld.portalindex[cluster->firstportal + cluster->numportals] = portalnum; - aasworld.portalindexsize++; - cluster->numportals++; - return qtrue; -} //end of the function AAS_UpdatePortal -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_FloodClusterAreas_r(int areanum, int clusternum) -{ - aas_area_t *area; - aas_face_t *face; - int facenum, i; - - // - if (areanum <= 0 || areanum >= aasworld.numareas) - { - AAS_Error("AAS_FloodClusterAreas_r: areanum out of range"); - return qfalse; - } //end if - //if the area is already part of a cluster - if (aasworld.areasettings[areanum].cluster > 0) - { - if (aasworld.areasettings[areanum].cluster == clusternum) return qtrue; - // - //there's a reachability going from one cluster to another only in one direction - // - AAS_Error("cluster %d touched cluster %d at area %d\r\n", - clusternum, aasworld.areasettings[areanum].cluster, areanum); - return qfalse; - } //end if - //don't add the cluster portal areas to the clusters - if (aasworld.areasettings[areanum].contents & AREACONTENTS_CLUSTERPORTAL) - { - return AAS_UpdatePortal(areanum, clusternum); - } //end if - //set the area cluster number - aasworld.areasettings[areanum].cluster = clusternum; - aasworld.areasettings[areanum].clusterareanum = - aasworld.clusters[clusternum].numareas; - //the cluster has an extra area - aasworld.clusters[clusternum].numareas++; - - area = &aasworld.areas[areanum]; - //use area faces to flood into adjacent areas - if (!nofaceflood) - { - for (i = 0; i < area->numfaces; i++) - { - facenum = abs(aasworld.faceindex[area->firstface + i]); - face = &aasworld.faces[facenum]; - if (face->frontarea == areanum) - { - if (face->backarea) if (!AAS_FloodClusterAreas_r(face->backarea, clusternum)) return qfalse; - } //end if - else - { - if (face->frontarea) if (!AAS_FloodClusterAreas_r(face->frontarea, clusternum)) return qfalse; - } //end else - } //end for - } //end if - //use the reachabilities to flood into other areas - for (i = 0; i < aasworld.areasettings[areanum].numreachableareas; i++) - { - if (!aasworld.reachability[ - aasworld.areasettings[areanum].firstreachablearea + i].areanum) - { - continue; - } //end if - if (!AAS_FloodClusterAreas_r(aasworld.reachability[ - aasworld.areasettings[areanum].firstreachablearea + i].areanum, clusternum)) return qfalse; - } //end for - return qtrue; -} //end of the function AAS_FloodClusterAreas_r -//=========================================================================== -// try to flood from all areas without cluster into areas with a cluster set -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_FloodClusterAreasUsingReachabilities(int clusternum) -{ - int i, j, areanum; - - for (i = 1; i < aasworld.numareas; i++) - { - //if this area already has a cluster set - if (aasworld.areasettings[i].cluster) - continue; - //if this area is a cluster portal - if (aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL) - continue; - //loop over the reachable areas from this area - for (j = 0; j < aasworld.areasettings[i].numreachableareas; j++) - { - //the reachable area - areanum = aasworld.reachability[aasworld.areasettings[i].firstreachablearea + j].areanum; - //if this area is a cluster portal - if (aasworld.areasettings[areanum].contents & AREACONTENTS_CLUSTERPORTAL) - continue; - //if this area has a cluster set - if (aasworld.areasettings[areanum].cluster) - { - if (!AAS_FloodClusterAreas_r(i, clusternum)) - return qfalse; - i = 0; - break; - } //end if - } //end for - } //end for - return qtrue; -} //end of the function AAS_FloodClusterAreasUsingReachabilities -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_NumberClusterPortals(int clusternum) -{ - int i, portalnum; - aas_cluster_t *cluster; - aas_portal_t *portal; - - cluster = &aasworld.clusters[clusternum]; - for (i = 0; i < cluster->numportals; i++) - { - portalnum = aasworld.portalindex[cluster->firstportal + i]; - portal = &aasworld.portals[portalnum]; - 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_NumberClusterPortals -//=========================================================================== -// -// 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 -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_FindClusters(void) -{ - int i; - aas_cluster_t *cluster; - - AAS_RemoveClusterAreas(); - // - for (i = 1; i < aasworld.numareas; i++) - { - //if the area is already part of a cluster - if (aasworld.areasettings[i].cluster) - continue; - // if not flooding through faces only use areas that have reachabilities - if (nofaceflood) - { - if (!aasworld.areasettings[i].numreachableareas) - continue; - } //end if - //if the area is a cluster portal - if (aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL) - continue; - if (aasworld.numclusters >= AAS_MAX_CLUSTERS) - { - AAS_Error("AAS_MAX_CLUSTERS"); - return qfalse; - } //end if - cluster = &aasworld.clusters[aasworld.numclusters]; - cluster->numareas = 0; - cluster->numreachabilityareas = 0; - cluster->firstportal = aasworld.portalindexsize; - cluster->numportals = 0; - //flood the areas in this cluster - if (!AAS_FloodClusterAreas_r(i, aasworld.numclusters)) - return qfalse; - if (!AAS_FloodClusterAreasUsingReachabilities(aasworld.numclusters)) - return qfalse; - //number the cluster areas - //AAS_NumberClusterPortals(aasworld.numclusters); - AAS_NumberClusterAreas(aasworld.numclusters); - //Log_Write("cluster %d has %d areas\r\n", aasworld.numclusters, cluster->numareas); - aasworld.numclusters++; - } //end for - return qtrue; -} //end of the function AAS_FindClusters -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_CreatePortals(void) -{ - int i; - aas_portal_t *portal; - - for (i = 1; i < aasworld.numareas; i++) - { - //if the area is a cluster portal - if (aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL) - { - if (aasworld.numportals >= AAS_MAX_PORTALS) - { - AAS_Error("AAS_MAX_PORTALS"); - return; - } //end if - portal = &aasworld.portals[aasworld.numportals]; - portal->areanum = i; - portal->frontcluster = 0; - portal->backcluster = 0; - aasworld.numportals++; - } //end if - } //end for -} //end of the function AAS_CreatePortals -/* -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_MapContainsTeleporters(void) -{ - bsp_entity_t *entities, *ent; - char *classname; - - entities = AAS_ParseBSPEntities(); - - for (ent = entities; ent; ent = ent->next) - { - classname = AAS_ValueForBSPEpairKey(ent, "classname"); - if (classname && !strcmp(classname, "misc_teleporter")) - { - AAS_FreeBSPEntities(entities); - return qtrue; - } //end if - } //end for - return qfalse; -} //end of the function AAS_MapContainsTeleporters -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_NonConvexFaces(aas_face_t *face1, aas_face_t *face2, int side1, int side2) -{ - int i, j, edgenum; - aas_plane_t *plane1, *plane2; - aas_edge_t *edge; - - - plane1 = &aasworld.planes[face1->planenum ^ side1]; - plane2 = &aasworld.planes[face2->planenum ^ side2]; - - //check if one of the points of face1 is at the back of the plane of face2 - for (i = 0; i < face1->numedges; i++) - { - edgenum = abs(aasworld.edgeindex[face1->firstedge + i]); - edge = &aasworld.edges[edgenum]; - for (j = 0; j < 2; j++) - { - if (DotProduct(plane2->normal, aasworld.vertexes[edge->v[j]]) - - plane2->dist < -0.01) return qtrue; - } //end for - } //end for - for (i = 0; i < face2->numedges; i++) - { - edgenum = abs(aasworld.edgeindex[face2->firstedge + i]); - edge = &aasworld.edges[edgenum]; - for (j = 0; j < 2; j++) - { - if (DotProduct(plane1->normal, aasworld.vertexes[edge->v[j]]) - - plane1->dist < -0.01) return qtrue; - } //end for - } //end for - - return qfalse; -} //end of the function AAS_NonConvexFaces -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -qboolean AAS_CanMergeAreas(int *areanums, int numareas) -{ - int i, j, s, face1num, face2num, side1, side2, fn1, fn2; - aas_face_t *face1, *face2; - aas_area_t *area1, *area2; - - for (i = 0; i < numareas; i++) - { - area1 = &aasworld.areas[areanums[i]]; - for (fn1 = 0; fn1 < area1->numfaces; fn1++) - { - face1num = abs(aasworld.faceindex[area1->firstface + fn1]); - face1 = &aasworld.faces[face1num]; - side1 = face1->frontarea != areanums[i]; - //check if the face isn't a shared one with one of the other areas - for (s = 0; s < numareas; s++) - { - if (s == i) continue; - if (face1->frontarea == s || face1->backarea == s) break; - } //end for - //if the face was a shared one - if (s != numareas) continue; - // - for (j = 0; j < numareas; j++) - { - if (j == i) continue; - area2 = &aasworld.areas[areanums[j]]; - for (fn2 = 0; fn2 < area2->numfaces; fn2++) - { - face2num = abs(aasworld.faceindex[area2->firstface + fn2]); - face2 = &aasworld.faces[face2num]; - side2 = face2->frontarea != areanums[j]; - //check if the face isn't a shared one with one of the other areas - for (s = 0; s < numareas; s++) - { - if (s == j) continue; - if (face2->frontarea == s || face2->backarea == s) break; - } //end for - //if the face was a shared one - if (s != numareas) continue; - // - if (AAS_NonConvexFaces(face1, face2, side1, side2)) return qfalse; - } //end for - } //end for - } //end for - } //end for - return qtrue; -} //end of the function AAS_CanMergeAreas -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -qboolean AAS_NonConvexEdges(aas_edge_t *edge1, aas_edge_t *edge2, int side1, int side2, int planenum) -{ - int i; - vec3_t edgevec1, edgevec2, normal1, normal2; - float dist1, dist2; - aas_plane_t *plane; - - plane = &aasworld.planes[planenum]; - VectorSubtract(aasworld.vertexes[edge1->v[1]], aasworld.vertexes[edge1->v[0]], edgevec1); - VectorSubtract(aasworld.vertexes[edge2->v[1]], aasworld.vertexes[edge2->v[0]], edgevec2); - if (side1) VectorInverse(edgevec1); - if (side2) VectorInverse(edgevec2); - // - CrossProduct(edgevec1, plane->normal, normal1); - dist1 = DotProduct(normal1, aasworld.vertexes[edge1->v[0]]); - CrossProduct(edgevec2, plane->normal, normal2); - dist2 = DotProduct(normal2, aasworld.vertexes[edge2->v[0]]); - - for (i = 0; i < 2; i++) - { - if (DotProduct(aasworld.vertexes[edge1->v[i]], normal2) - dist2 < -0.01) return qfalse; - } //end for - for (i = 0; i < 2; i++) - { - if (DotProduct(aasworld.vertexes[edge2->v[i]], normal1) - dist1 < -0.01) return qfalse; - } //end for - return qtrue; -} //end of the function AAS_NonConvexEdges -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -qboolean AAS_CanMergeFaces(int *facenums, int numfaces, int planenum) -{ - int i, j, s, edgenum1, edgenum2, side1, side2, en1, en2, ens; - aas_face_t *face1, *face2, *otherface; - aas_edge_t *edge1, *edge2; - - for (i = 0; i < numfaces; i++) - { - face1 = &aasworld.faces[facenums[i]]; - for (en1 = 0; en1 < face1->numedges; en1++) - { - edgenum1 = aasworld.edgeindex[face1->firstedge + en1]; - side1 = (edgenum1 < 0) ^ (face1->planenum != planenum); - edgenum1 = abs(edgenum1); - edge1 = &aasworld.edges[edgenum1]; - //check if the edge is shared with another face - for (s = 0; s < numfaces; s++) - { - if (s == i) continue; - otherface = &aasworld.faces[facenums[s]]; - for (ens = 0; ens < otherface->numedges; ens++) - { - if (edgenum1 == abs(aasworld.edgeindex[otherface->firstedge + ens])) break; - } //end for - if (ens != otherface->numedges) break; - } //end for - //if the edge was shared - if (s != numfaces) continue; - // - for (j = 0; j < numfaces; j++) - { - if (j == i) continue; - face2 = &aasworld.faces[facenums[j]]; - for (en2 = 0; en2 < face2->numedges; en2++) - { - edgenum2 = aasworld.edgeindex[face2->firstedge + en2]; - side2 = (edgenum2 < 0) ^ (face2->planenum != planenum); - edgenum2 = abs(edgenum2); - edge2 = &aasworld.edges[edgenum2]; - //check if the edge is shared with another face - for (s = 0; s < numfaces; s++) - { - if (s == i) continue; - otherface = &aasworld.faces[facenums[s]]; - for (ens = 0; ens < otherface->numedges; ens++) - { - if (edgenum2 == abs(aasworld.edgeindex[otherface->firstedge + ens])) break; - } //end for - if (ens != otherface->numedges) break; - } //end for - //if the edge was shared - if (s != numfaces) continue; - // - if (AAS_NonConvexEdges(edge1, edge2, side1, side2, planenum)) return qfalse; - } //end for - } //end for - } //end for - } //end for - return qtrue; -} //end of the function AAS_CanMergeFaces*/ -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_ConnectedAreas_r(int *areanums, int numareas, int *connectedareas, int curarea) -{ - int i, j, otherareanum, facenum; - aas_area_t *area; - aas_face_t *face; - - connectedareas[curarea] = qtrue; - area = &aasworld.areas[areanums[curarea]]; - for (i = 0; i < area->numfaces; i++) - { - facenum = abs(aasworld.faceindex[area->firstface + i]); - face = &aasworld.faces[facenum]; - //if the face is solid - if (face->faceflags & FACE_SOLID) continue; - //get the area at the other side of the face - if (face->frontarea != areanums[curarea]) otherareanum = face->frontarea; - else otherareanum = face->backarea; - //check if the face is leading to one of the other areas - for (j = 0; j < numareas; j++) - { - if (areanums[j] == otherareanum) break; - } //end for - //if the face isn't leading to one of the other areas - if (j == numareas) continue; - //if the other area is already connected - if (connectedareas[j]) continue; - //recursively proceed with the other area - AAS_ConnectedAreas_r(areanums, numareas, connectedareas, j); - } //end for -} //end of the function AAS_ConnectedAreas_r -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -qboolean AAS_ConnectedAreas(int *areanums, int numareas) -{ - int connectedareas[MAX_PORTALAREAS], i; - - Com_Memset(connectedareas, 0, sizeof(connectedareas)); - if (numareas < 1) return qfalse; - if (numareas == 1) return qtrue; - AAS_ConnectedAreas_r(areanums, numareas, connectedareas, 0); - for (i = 0; i < numareas; i++) - { - if (!connectedareas[i]) return qfalse; - } //end for - return qtrue; -} //end of the function AAS_ConnectedAreas -//=========================================================================== -// gets adjacent areas with less presence types recursively -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_GetAdjacentAreasWithLessPresenceTypes_r(int *areanums, int numareas, int curareanum) -{ - int i, j, presencetype, otherpresencetype, otherareanum, facenum; - aas_area_t *area; - aas_face_t *face; - - areanums[numareas++] = curareanum; - area = &aasworld.areas[curareanum]; - presencetype = aasworld.areasettings[curareanum].presencetype; - for (i = 0; i < area->numfaces; i++) - { - facenum = abs(aasworld.faceindex[area->firstface + i]); - face = &aasworld.faces[facenum]; - //if the face is solid - if (face->faceflags & FACE_SOLID) continue; - //the area at the other side of the face - if (face->frontarea != curareanum) otherareanum = face->frontarea; - else otherareanum = face->backarea; - // - otherpresencetype = aasworld.areasettings[otherareanum].presencetype; - //if the other area has less presence types - if ((presencetype & ~otherpresencetype) && - !(otherpresencetype & ~presencetype)) - { - //check if the other area isn't already in the list - for (j = 0; j < numareas; j++) - { - if (otherareanum == areanums[j]) break; - } //end for - //if the other area isn't already in the list - if (j == numareas) - { - if (numareas >= MAX_PORTALAREAS) - { - AAS_Error("MAX_PORTALAREAS"); - return numareas; - } //end if - numareas = AAS_GetAdjacentAreasWithLessPresenceTypes_r(areanums, numareas, otherareanum); - } //end if - } //end if - } //end for - return numareas; -} //end of the function AAS_GetAdjacentAreasWithLessPresenceTypes_r -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_CheckAreaForPossiblePortals(int areanum) -{ - int i, j, k, fen, ben, frontedgenum, backedgenum, facenum; - int areanums[MAX_PORTALAREAS], numareas, otherareanum; - int numareafrontfaces[MAX_PORTALAREAS], numareabackfaces[MAX_PORTALAREAS]; - int frontfacenums[MAX_PORTALAREAS], backfacenums[MAX_PORTALAREAS]; - int numfrontfaces, numbackfaces; - int frontareanums[MAX_PORTALAREAS], backareanums[MAX_PORTALAREAS]; - int numfrontareas, numbackareas; - int frontplanenum, backplanenum, faceplanenum; - aas_area_t *area; - aas_face_t *frontface, *backface, *face; - - //if it isn't already a portal - if (aasworld.areasettings[areanum].contents & AREACONTENTS_CLUSTERPORTAL) return 0; - //it must be a grounded area - if (!(aasworld.areasettings[areanum].areaflags & AREA_GROUNDED)) return 0; - // - Com_Memset(numareafrontfaces, 0, sizeof(numareafrontfaces)); - Com_Memset(numareabackfaces, 0, sizeof(numareabackfaces)); - numareas = numfrontfaces = numbackfaces = 0; - numfrontareas = numbackareas = 0; - frontplanenum = backplanenum = -1; - //add any adjacent areas with less presence types - numareas = AAS_GetAdjacentAreasWithLessPresenceTypes_r(areanums, 0, areanum); - // - for (i = 0; i < numareas; i++) - { - area = &aasworld.areas[areanums[i]]; - for (j = 0; j < area->numfaces; j++) - { - facenum = abs(aasworld.faceindex[area->firstface + j]); - face = &aasworld.faces[facenum]; - //if the face is solid - if (face->faceflags & FACE_SOLID) continue; - //check if the face is shared with one of the other areas - for (k = 0; k < numareas; k++) - { - if (k == i) continue; - if (face->frontarea == areanums[k] || face->backarea == areanums[k]) break; - } //end for - //if the face is shared - if (k != numareas) continue; - //the number of the area at the other side of the face - if (face->frontarea == areanums[i]) otherareanum = face->backarea; - else otherareanum = face->frontarea; - //if the other area already is a cluter portal - if (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL) return 0; - //number of the plane of the area - faceplanenum = face->planenum & ~1; - // - if (frontplanenum < 0 || faceplanenum == frontplanenum) - { - frontplanenum = faceplanenum; - frontfacenums[numfrontfaces++] = facenum; - for (k = 0; k < numfrontareas; k++) - { - if (frontareanums[k] == otherareanum) break; - } //end for - if (k == numfrontareas) frontareanums[numfrontareas++] = otherareanum; - numareafrontfaces[i]++; - } //end if - else if (backplanenum < 0 || faceplanenum == backplanenum) - { - backplanenum = faceplanenum; - backfacenums[numbackfaces++] = facenum; - for (k = 0; k < numbackareas; k++) - { - if (backareanums[k] == otherareanum) break; - } //end for - if (k == numbackareas) backareanums[numbackareas++] = otherareanum; - numareabackfaces[i]++; - } //end else - else - { - return 0; - } //end else - } //end for - } //end for - //every area should have at least one front face and one back face - for (i = 0; i < numareas; i++) - { - if (!numareafrontfaces[i] || !numareabackfaces[i]) return 0; - } //end for - //the front areas should all be connected - if (!AAS_ConnectedAreas(frontareanums, numfrontareas)) return 0; - //the back areas should all be connected - if (!AAS_ConnectedAreas(backareanums, numbackareas)) return 0; - //none of the front faces should have a shared edge with a back face - for (i = 0; i < numfrontfaces; i++) - { - frontface = &aasworld.faces[frontfacenums[i]]; - for (fen = 0; fen < frontface->numedges; fen++) - { - frontedgenum = abs(aasworld.edgeindex[frontface->firstedge + fen]); - for (j = 0; j < numbackfaces; j++) - { - backface = &aasworld.faces[backfacenums[j]]; - for (ben = 0; ben < backface->numedges; ben++) - { - backedgenum = abs(aasworld.edgeindex[backface->firstedge + ben]); - if (frontedgenum == backedgenum) break; - } //end for - if (ben != backface->numedges) break; - } //end for - if (j != numbackfaces) break; - } //end for - if (fen != frontface->numedges) break; - } //end for - if (i != numfrontfaces) return 0; - //set the cluster portal contents - for (i = 0; i < numareas; i++) - { - aasworld.areasettings[areanums[i]].contents |= AREACONTENTS_CLUSTERPORTAL; - //this area can be used as a route portal - aasworld.areasettings[areanums[i]].contents |= AREACONTENTS_ROUTEPORTAL; - Log_Write("possible portal: %d\r\n", areanums[i]); - } //end for - // - return numareas; -} //end of the function AAS_CheckAreaForPossiblePortals -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_FindPossiblePortals(void) -{ - int i, numpossibleportals; - - numpossibleportals = 0; - for (i = 1; i < aasworld.numareas; i++) - { - numpossibleportals += AAS_CheckAreaForPossiblePortals(i); - } //end for - botimport.Print(PRT_MESSAGE, "\r%6d possible portal areas\n", numpossibleportals); -} //end of the function AAS_FindPossiblePortals -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_RemoveAllPortals(void) -{ - int i; - - for (i = 1; i < aasworld.numareas; i++) - { - aasworld.areasettings[i].contents &= ~AREACONTENTS_CLUSTERPORTAL; - } //end for -} //end of the function AAS_RemoveAllPortals - -#if 0 -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_FloodCluster_r(int areanum, int clusternum) -{ - int i, otherareanum; - aas_face_t *face; - aas_area_t *area; - - //set cluster mark - aasworld.areasettings[areanum].cluster = clusternum; - //if the area is a portal - //if (aasworld.areasettings[areanum].contents & AREACONTENTS_CLUSTERPORTAL) return; - // - area = &aasworld.areas[areanum]; - //use area faces to flood into adjacent areas - for (i = 0; i < area->numfaces; i++) - { - face = &aasworld.faces[abs(aasworld.faceindex[area->firstface + i])]; - // - if (face->frontarea != areanum) otherareanum = face->frontarea; - else otherareanum = face->backarea; - //if there's no area at the other side - if (!otherareanum) continue; - //if the area is a portal - if (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL) continue; - //if the area is already marked - if (aasworld.areasettings[otherareanum].cluster) continue; - // - AAS_FloodCluster_r(otherareanum, clusternum); - } //end for - //use the reachabilities to flood into other areas - for (i = 0; i < aasworld.areasettings[areanum].numreachableareas; i++) - { - otherareanum = aasworld.reachability[ - aasworld.areasettings[areanum].firstreachablearea + i].areanum; - if (!otherareanum) - { - continue; - AAS_Error("reachability %d has zero area\n", aasworld.areasettings[areanum].firstreachablearea + i); - } //end if - //if the area is a portal - if (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL) continue; - //if the area is already marked - if (aasworld.areasettings[otherareanum].cluster) continue; - // - AAS_FloodCluster_r(otherareanum, clusternum); - } //end for -} //end of the function AAS_FloodCluster_r -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_RemoveTeleporterPortals(void) -{ - int i, j, areanum; - - for (i = 1; i < aasworld.numareas; i++) - { - for (j = 0; j < aasworld.areasettings[i].numreachableareas; j++) - { - areanum = aasworld.reachability[aasworld.areasettings[i].firstreachablearea + j].areanum; - if (aasworld.reachability[aasworld.areasettings[i].firstreachablearea + j].traveltype == TRAVEL_TELEPORT) - { - aasworld.areasettings[i].contents &= ~AREACONTENTS_CLUSTERPORTAL; - aasworld.areasettings[areanum].contents &= ~AREACONTENTS_CLUSTERPORTAL; - break; - } //end if - } //end for - } //end for -} //end of the function AAS_RemoveTeleporterPortals -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_FloodClusterReachabilities(int clusternum) -{ - int i, j, areanum; - - for (i = 1; i < aasworld.numareas; i++) - { - //if this area already has a cluster set - if (aasworld.areasettings[i].cluster) continue; - //if this area is a cluster portal - if (aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL) continue; - //loop over the reachable areas from this area - for (j = 0; j < aasworld.areasettings[i].numreachableareas; j++) - { - //the reachable area - areanum = aasworld.reachability[aasworld.areasettings[i].firstreachablearea + j].areanum; - //if this area is a cluster portal - if (aasworld.areasettings[areanum].contents & AREACONTENTS_CLUSTERPORTAL) continue; - //if this area has a cluster set - if (aasworld.areasettings[areanum].cluster == clusternum) - { - AAS_FloodCluster_r(i, clusternum); - i = 0; - break; - } //end if - } //end for - } //end for -} //end of the function AAS_FloodClusterReachabilities - -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_RemoveNotClusterClosingPortals(void) -{ - int i, j, k, facenum, otherareanum, nonclosingportals; - aas_area_t *area; - aas_face_t *face; - - AAS_RemoveTeleporterPortals(); - // - nonclosingportals = 0; - for (i = 1; i < aasworld.numareas; i++) - { - if (!(aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL)) continue; - //find a non-portal area adjacent to the portal area and flood - //the cluster from there - area = &aasworld.areas[i]; - for (j = 0; j < area->numfaces; j++) - { - facenum = abs(aasworld.faceindex[area->firstface + j]); - face = &aasworld.faces[facenum]; - // - if (face->frontarea != i) otherareanum = face->frontarea; - else otherareanum = face->backarea; - // - if (!otherareanum) continue; - // - if (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL) - { - continue; - } //end if - //reset all cluster fields - AAS_RemoveClusterAreas(); - // - AAS_FloodCluster_r(otherareanum, 1); - AAS_FloodClusterReachabilities(1); - //check if all adjacent non-portal areas have a cluster set - for (k = 0; k < area->numfaces; k++) - { - facenum = abs(aasworld.faceindex[area->firstface + k]); - face = &aasworld.faces[facenum]; - // - if (face->frontarea != i) otherareanum = face->frontarea; - else otherareanum = face->backarea; - // - if (!otherareanum) continue; - // - if (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL) - { - continue; - } //end if - // - if (!aasworld.areasettings[otherareanum].cluster) break; - } //end for - //if all adjacent non-portal areas have a cluster set then the portal - //didn't seal a cluster - if (k >= area->numfaces) - { - aasworld.areasettings[i].contents &= ~AREACONTENTS_CLUSTERPORTAL; - nonclosingportals++; - //recheck all the other portals again - i = 0; - break; - } //end if - } //end for - } //end for - botimport.Print(PRT_MESSAGE, "\r%6d non closing portals removed\n", nonclosingportals); -} //end of the function AAS_RemoveNotClusterClosingPortals - -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== - -void AAS_RemoveNotClusterClosingPortals(void) -{ - int i, j, facenum, otherareanum, nonclosingportals, numseperatedclusters; - aas_area_t *area; - aas_face_t *face; - - AAS_RemoveTeleporterPortals(); - // - nonclosingportals = 0; - for (i = 1; i < aasworld.numareas; i++) - { - if (!(aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL)) continue; - // - numseperatedclusters = 0; - //reset all cluster fields - AAS_RemoveClusterAreas(); - //find a non-portal area adjacent to the portal area and flood - //the cluster from there - area = &aasworld.areas[i]; - for (j = 0; j < area->numfaces; j++) - { - facenum = abs(aasworld.faceindex[area->firstface + j]); - face = &aasworld.faces[facenum]; - // - if (face->frontarea != i) otherareanum = face->frontarea; - else otherareanum = face->backarea; - //if not solid at the other side of the face - if (!otherareanum) continue; - //don't flood into other portals - if (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL) continue; - //if the area already has a cluster set - if (aasworld.areasettings[otherareanum].cluster) continue; - //another cluster is seperated by this portal - numseperatedclusters++; - //flood the cluster - AAS_FloodCluster_r(otherareanum, numseperatedclusters); - AAS_FloodClusterReachabilities(numseperatedclusters); - } //end for - //use the reachabilities to flood into other areas - for (j = 0; j < aasworld.areasettings[i].numreachableareas; j++) - { - otherareanum = aasworld.reachability[ - aasworld.areasettings[i].firstreachablearea + j].areanum; - //this should never be qtrue but we check anyway - if (!otherareanum) continue; - //don't flood into other portals - if (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL) continue; - //if the area already has a cluster set - if (aasworld.areasettings[otherareanum].cluster) continue; - //another cluster is seperated by this portal - numseperatedclusters++; - //flood the cluster - AAS_FloodCluster_r(otherareanum, numseperatedclusters); - AAS_FloodClusterReachabilities(numseperatedclusters); - } //end for - //a portal must seperate no more and no less than 2 clusters - if (numseperatedclusters != 2) - { - aasworld.areasettings[i].contents &= ~AREACONTENTS_CLUSTERPORTAL; - nonclosingportals++; - //recheck all the other portals again - i = 0; - } //end if - } //end for - botimport.Print(PRT_MESSAGE, "\r%6d non closing portals removed\n", nonclosingportals); -} //end of the function AAS_RemoveNotClusterClosingPortals - -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== - -void AAS_AddTeleporterPortals(void) -{ - int j, area2num, facenum, otherareanum; - char *target, *targetname, *classname; - bsp_entity_t *entities, *ent, *dest; - vec3_t origin, destorigin, mins, maxs, end; - vec3_t bbmins, bbmaxs; - aas_area_t *area; - aas_face_t *face; - aas_trace_t trace; - aas_link_t *areas, *link; - - entities = AAS_ParseBSPEntities(); - - for (ent = entities; ent; ent = ent->next) - { - classname = AAS_ValueForBSPEpairKey(ent, "classname"); - if (classname && !strcmp(classname, "misc_teleporter")) - { - if (!AAS_VectorForBSPEpairKey(ent, "origin", origin)) - { - botimport.Print(PRT_ERROR, "teleporter (%s) without origin\n", target); - continue; - } //end if - // - target = AAS_ValueForBSPEpairKey(ent, "target"); - if (!target) - { - botimport.Print(PRT_ERROR, "teleporter (%s) without target\n", target); - continue; - } //end if - for (dest = entities; dest; dest = dest->next) - { - classname = AAS_ValueForBSPEpairKey(dest, "classname"); - if (classname && !strcmp(classname, "misc_teleporter_dest")) - { - targetname = AAS_ValueForBSPEpairKey(dest, "targetname"); - if (targetname && !strcmp(targetname, target)) - { - break; - } //end if - } //end if - } //end for - if (!dest) - { - botimport.Print(PRT_ERROR, "teleporter without destination (%s)\n", target); - continue; - } //end if - if (!AAS_VectorForBSPEpairKey(dest, "origin", destorigin)) - { - botimport.Print(PRT_ERROR, "teleporter destination (%s) without origin\n", target); - continue; - } //end if - destorigin[2] += 24; //just for q2e1m2, the dork has put the telepads in the ground - VectorCopy(destorigin, end); - end[2] -= 100; - trace = AAS_TraceClientBBox(destorigin, end, PRESENCE_CROUCH, -1); - if (trace.startsolid) - { - botimport.Print(PRT_ERROR, "teleporter destination (%s) in solid\n", target); - continue; - } //end if - VectorCopy(trace.endpos, destorigin); - area2num = AAS_PointAreaNum(destorigin); - //reset all cluster fields - for (j = 0; j < aasworld.numareas; j++) - { - aasworld.areasettings[j].cluster = 0; - } //end for - // - VectorSet(mins, -8, -8, 8); - VectorSet(maxs, 8, 8, 24); - // - AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, bbmins, bbmaxs); - // - VectorAdd(origin, mins, mins); - VectorAdd(origin, maxs, maxs); - //add bounding box size - VectorSubtract(mins, bbmaxs, mins); - VectorSubtract(maxs, bbmins, maxs); - //link an invalid (-1) entity - areas = AAS_AASLinkEntity(mins, maxs, -1); - // - for (link = areas; link; link = link->next_area) - { - if (!AAS_AreaGrounded(link->areanum)) continue; - //add the teleporter portal mark - aasworld.areasettings[link->areanum].contents |= AREACONTENTS_CLUSTERPORTAL | - AREACONTENTS_TELEPORTAL; - } //end for - // - for (link = areas; link; link = link->next_area) - { - if (!AAS_AreaGrounded(link->areanum)) continue; - //find a non-portal area adjacent to the portal area and flood - //the cluster from there - area = &aasworld.areas[link->areanum]; - for (j = 0; j < area->numfaces; j++) - { - facenum = abs(aasworld.faceindex[area->firstface + j]); - face = &aasworld.faces[facenum]; - // - if (face->frontarea != link->areanum) otherareanum = face->frontarea; - else otherareanum = face->backarea; - // - if (!otherareanum) continue; - // - if (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL) - { - continue; - } //end if - // - AAS_FloodCluster_r(otherareanum, 1); - } //end for - } //end for - //if the teleport destination IS in the same cluster - if (aasworld.areasettings[area2num].cluster) - { - for (link = areas; link; link = link->next_area) - { - if (!AAS_AreaGrounded(link->areanum)) continue; - //add the teleporter portal mark - aasworld.areasettings[link->areanum].contents &= ~(AREACONTENTS_CLUSTERPORTAL | - AREACONTENTS_TELEPORTAL); - } //end for - } //end if - } //end if - } //end for - AAS_FreeBSPEntities(entities); -} //end of the function AAS_AddTeleporterPortals - -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_AddTeleporterPortals(void) -{ - int i, j, areanum; - - for (i = 1; i < aasworld.numareas; i++) - { - for (j = 0; j < aasworld.areasettings[i].numreachableareas; j++) - { - if (aasworld.reachability[aasworld.areasettings[i].firstreachablearea + j].traveltype != TRAVEL_TELEPORT) continue; - areanum = aasworld.reachability[aasworld.areasettings[i].firstreachablearea + j].areanum; - aasworld.areasettings[areanum].contents |= AREACONTENTS_CLUSTERPORTAL; - } //end for - } //end for -} //end of the function AAS_AddTeleporterPortals - -#endif - -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_TestPortals(void) -{ - int i; - aas_portal_t *portal; - - for (i = 1; i < aasworld.numportals; i++) - { - portal = &aasworld.portals[i]; - if (!portal->frontcluster) - { - aasworld.areasettings[portal->areanum].contents &= ~AREACONTENTS_CLUSTERPORTAL; - Log_Write("portal area %d has no front cluster\r\n", portal->areanum); - return qfalse; - } //end if - if (!portal->backcluster) - { - aasworld.areasettings[portal->areanum].contents &= ~AREACONTENTS_CLUSTERPORTAL; - Log_Write("portal area %d has no back cluster\r\n", portal->areanum); - return qfalse; - } //end if - } //end for - return qtrue; -} //end of the function -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_CountForcedClusterPortals(void) -{ - int num, i; - - num = 0; - for (i = 1; i < aasworld.numareas; i++) - { - if (aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL) - { - Log_Write("area %d is a forced portal area\r\n", i); - num++; - } //end if - } //end for - botimport.Print(PRT_MESSAGE, "%6d forced portal areas\n", num); -} //end of the function AAS_CountForcedClusterPortals -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_CreateViewPortals(void) -{ - int i; - - for (i = 1; i < aasworld.numareas; i++) - { - if (aasworld.areasettings[i].contents & AREACONTENTS_CLUSTERPORTAL) - { - aasworld.areasettings[i].contents |= AREACONTENTS_VIEWPORTAL; - } //end if - } //end for -} //end of the function AAS_CreateViewPortals -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_SetViewPortalsAsClusterPortals(void) -{ - int i; - - for (i = 1; i < aasworld.numareas; i++) - { - if (aasworld.areasettings[i].contents & AREACONTENTS_VIEWPORTAL) - { - aasworld.areasettings[i].contents |= AREACONTENTS_CLUSTERPORTAL; - } //end if - } //end for -} //end of the function AAS_SetViewPortalsAsClusterPortals -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_InitClustering(void) -{ - int i, removedPortalAreas; - int n, total, numreachabilityareas; - - if (!aasworld.loaded) return; - //if there are clusters - if (aasworld.numclusters >= 1) - { -#ifndef BSPC - //if clustering isn't forced - if (!((int)LibVarGetValue("forceclustering")) && - !((int)LibVarGetValue("forcereachability"))) return; -#endif - } //end if - //set all view portals as cluster portals in case we re-calculate the reachabilities and clusters (with -reach) - AAS_SetViewPortalsAsClusterPortals(); - //count the number of forced cluster portals - AAS_CountForcedClusterPortals(); - //remove all area cluster marks - AAS_RemoveClusterAreas(); - //find possible cluster portals - AAS_FindPossiblePortals(); - //craete portals to for the bot view - AAS_CreateViewPortals(); - //remove all portals that are not closing a cluster - //AAS_RemoveNotClusterClosingPortals(); - //initialize portal memory - if (aasworld.portals) FreeMemory(aasworld.portals); - aasworld.portals = (aas_portal_t *) GetClearedMemory(AAS_MAX_PORTALS * sizeof(aas_portal_t)); - //initialize portal index memory - if (aasworld.portalindex) FreeMemory(aasworld.portalindex); - aasworld.portalindex = (aas_portalindex_t *) GetClearedMemory(AAS_MAX_PORTALINDEXSIZE * sizeof(aas_portalindex_t)); - //initialize cluster memory - if (aasworld.clusters) FreeMemory(aasworld.clusters); - aasworld.clusters = (aas_cluster_t *) GetClearedMemory(AAS_MAX_CLUSTERS * sizeof(aas_cluster_t)); - // - removedPortalAreas = 0; - botimport.Print(PRT_MESSAGE, "\r%6d removed portal areas", removedPortalAreas); - while(1) - { - botimport.Print(PRT_MESSAGE, "\r%6d", removedPortalAreas); - //initialize the number of portals and clusters - aasworld.numportals = 1; //portal 0 is a dummy - aasworld.portalindexsize = 0; - aasworld.numclusters = 1; //cluster 0 is a dummy - //create the portals from the portal areas - AAS_CreatePortals(); - // - removedPortalAreas++; - //find the clusters - if (!AAS_FindClusters()) - continue; - //test the portals - if (!AAS_TestPortals()) - continue; - // - break; - } //end while - botimport.Print(PRT_MESSAGE, "\n"); - //the AAS file should be saved - aasworld.savefile = qtrue; - //write the portal areas to the log file - for (i = 1; i < aasworld.numportals; i++) - { - Log_Write("portal %d: area %d\r\n", i, aasworld.portals[i].areanum); - } //end for - // report cluster info - botimport.Print(PRT_MESSAGE, "%6d portals created\n", aasworld.numportals); - botimport.Print(PRT_MESSAGE, "%6d clusters created\n", aasworld.numclusters); - for (i = 1; i < aasworld.numclusters; i++) - { - botimport.Print(PRT_MESSAGE, "cluster %d has %d reachability areas\n", i, - aasworld.clusters[i].numreachabilityareas); - } //end for - // report AAS file efficiency - numreachabilityareas = 0; - total = 0; - for (i = 0; i < aasworld.numclusters; i++) { - n = aasworld.clusters[i].numreachabilityareas; - numreachabilityareas += n; - total += n * n; - } - total += numreachabilityareas * aasworld.numportals; - // - botimport.Print(PRT_MESSAGE, "%6i total reachability areas\n", numreachabilityareas); - botimport.Print(PRT_MESSAGE, "%6i AAS memory/CPU usage (the lower the better)\n", total * 3); -} //end of the function AAS_InitClustering diff --git a/src/botlib/be_aas_cluster.h b/src/botlib/be_aas_cluster.h deleted file mode 100644 index 24ef9a1c..00000000 --- a/src/botlib/be_aas_cluster.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_aas_cluster.h - * - * desc: AAS - * - * $Archive: /source/code/botlib/be_aas_cluster.h $ - * - *****************************************************************************/ - -#ifdef AASINTERN -//initialize the AAS clustering -void AAS_InitClustering(void); -// -void AAS_SetViewPortalsAsClusterPortals(void); -#endif //AASINTERN - diff --git a/src/botlib/be_aas_debug.c b/src/botlib/be_aas_debug.c deleted file mode 100644 index 2d6d9412..00000000 --- a/src/botlib/be_aas_debug.c +++ /dev/null @@ -1,778 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_aas_debug.c - * - * desc: AAS debug code - * - * $Archive: /MissionPack/code/botlib/be_aas_debug.c $ - * - *****************************************************************************/ - -#include "../qcommon/q_shared.h" -#include "l_memory.h" -#include "l_script.h" -#include "l_precomp.h" -#include "l_struct.h" -#include "l_libvar.h" -#include "aasfile.h" -#include "botlib.h" -#include "be_aas.h" -#include "be_interface.h" -#include "be_aas_funcs.h" -#include "be_aas_def.h" - -#define MAX_DEBUGLINES 1024 -#define MAX_DEBUGPOLYGONS 8192 - -int debuglines[MAX_DEBUGLINES]; -int debuglinevisible[MAX_DEBUGLINES]; -int numdebuglines; - -static int debugpolygons[MAX_DEBUGPOLYGONS]; - -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_ClearShownPolygons(void) -{ - int i; -//* - for (i = 0; i < MAX_DEBUGPOLYGONS; i++) - { - if (debugpolygons[i]) botimport.DebugPolygonDelete(debugpolygons[i]); - debugpolygons[i] = 0; - } //end for -//*/ -/* - for (i = 0; i < MAX_DEBUGPOLYGONS; i++) - { - botimport.DebugPolygonDelete(i); - debugpolygons[i] = 0; - } //end for -*/ -} //end of the function AAS_ClearShownPolygons -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_ShowPolygon(int color, int numpoints, vec3_t *points) -{ - int i; - - for (i = 0; i < MAX_DEBUGPOLYGONS; i++) - { - if (!debugpolygons[i]) - { - debugpolygons[i] = botimport.DebugPolygonCreate(color, numpoints, points); - break; - } //end if - } //end for -} //end of the function AAS_ShowPolygon -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_ClearShownDebugLines(void) -{ - int i; - - //make all lines invisible - for (i = 0; i < MAX_DEBUGLINES; i++) - { - if (debuglines[i]) - { - //botimport.DebugLineShow(debuglines[i], NULL, NULL, LINECOLOR_NONE); - botimport.DebugLineDelete(debuglines[i]); - debuglines[i] = 0; - debuglinevisible[i] = qfalse; - } //end if - } //end for -} //end of the function AAS_ClearShownDebugLines -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_DebugLine(vec3_t start, vec3_t end, int color) -{ - int line; - - for (line = 0; line < MAX_DEBUGLINES; line++) - { - if (!debuglines[line]) - { - debuglines[line] = botimport.DebugLineCreate(); - debuglinevisible[line] = qfalse; - numdebuglines++; - } //end if - if (!debuglinevisible[line]) - { - botimport.DebugLineShow(debuglines[line], start, end, color); - debuglinevisible[line] = qtrue; - return; - } //end else - } //end for -} //end of the function AAS_DebugLine -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_PermanentLine(vec3_t start, vec3_t end, int color) -{ - int line; - - line = botimport.DebugLineCreate(); - botimport.DebugLineShow(line, start, end, color); -} //end of the function AAS_PermenentLine -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_DrawPermanentCross(vec3_t origin, float size, int color) -{ - int i, debugline; - vec3_t start, end; - - for (i = 0; i < 3; i++) - { - VectorCopy(origin, start); - start[i] += size; - VectorCopy(origin, end); - end[i] -= size; - AAS_DebugLine(start, end, color); - debugline = botimport.DebugLineCreate(); - botimport.DebugLineShow(debugline, start, end, color); - } //end for -} //end of the function AAS_DrawPermanentCross -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_DrawPlaneCross(vec3_t point, vec3_t normal, float dist, int type, int color) -{ - int n0, n1, n2, j, line, lines[2]; - vec3_t start1, end1, start2, end2; - - //make a cross in the hit plane at the hit point - VectorCopy(point, start1); - VectorCopy(point, end1); - VectorCopy(point, start2); - VectorCopy(point, end2); - - n0 = type % 3; - n1 = (type + 1) % 3; - n2 = (type + 2) % 3; - start1[n1] -= 6; - start1[n2] -= 6; - end1[n1] += 6; - end1[n2] += 6; - start2[n1] += 6; - start2[n2] -= 6; - end2[n1] -= 6; - end2[n2] += 6; - - start1[n0] = (dist - (start1[n1] * normal[n1] + - start1[n2] * normal[n2])) / normal[n0]; - end1[n0] = (dist - (end1[n1] * normal[n1] + - end1[n2] * normal[n2])) / normal[n0]; - start2[n0] = (dist - (start2[n1] * normal[n1] + - start2[n2] * normal[n2])) / normal[n0]; - end2[n0] = (dist - (end2[n1] * normal[n1] + - end2[n2] * normal[n2])) / normal[n0]; - - for (j = 0, line = 0; j < 2 && line < MAX_DEBUGLINES; line++) - { - if (!debuglines[line]) - { - debuglines[line] = botimport.DebugLineCreate(); - lines[j++] = debuglines[line]; - debuglinevisible[line] = qtrue; - numdebuglines++; - } //end if - else if (!debuglinevisible[line]) - { - lines[j++] = debuglines[line]; - debuglinevisible[line] = qtrue; - } //end else - } //end for - botimport.DebugLineShow(lines[0], start1, end1, color); - botimport.DebugLineShow(lines[1], start2, end2, color); -} //end of the function AAS_DrawPlaneCross -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_ShowBoundingBox(vec3_t origin, vec3_t mins, vec3_t maxs) -{ - vec3_t bboxcorners[8]; - int lines[3]; - int i, j, line; - - //upper corners - bboxcorners[0][0] = origin[0] + maxs[0]; - bboxcorners[0][1] = origin[1] + maxs[1]; - bboxcorners[0][2] = origin[2] + maxs[2]; - // - bboxcorners[1][0] = origin[0] + mins[0]; - bboxcorners[1][1] = origin[1] + maxs[1]; - bboxcorners[1][2] = origin[2] + maxs[2]; - // - bboxcorners[2][0] = origin[0] + mins[0]; - bboxcorners[2][1] = origin[1] + mins[1]; - bboxcorners[2][2] = origin[2] + maxs[2]; - // - bboxcorners[3][0] = origin[0] + maxs[0]; - bboxcorners[3][1] = origin[1] + mins[1]; - bboxcorners[3][2] = origin[2] + maxs[2]; - //lower corners - Com_Memcpy(bboxcorners[4], bboxcorners[0], sizeof(vec3_t) * 4); - for (i = 0; i < 4; i++) bboxcorners[4 + i][2] = origin[2] + mins[2]; - //draw bounding box - for (i = 0; i < 4; i++) - { - for (j = 0, line = 0; j < 3 && line < MAX_DEBUGLINES; line++) - { - if (!debuglines[line]) - { - debuglines[line] = botimport.DebugLineCreate(); - lines[j++] = debuglines[line]; - debuglinevisible[line] = qtrue; - numdebuglines++; - } //end if - else if (!debuglinevisible[line]) - { - lines[j++] = debuglines[line]; - debuglinevisible[line] = qtrue; - } //end else - } //end for - //top plane - botimport.DebugLineShow(lines[0], bboxcorners[i], - bboxcorners[(i+1)&3], LINECOLOR_RED); - //bottom plane - botimport.DebugLineShow(lines[1], bboxcorners[4+i], - bboxcorners[4+((i+1)&3)], LINECOLOR_RED); - //vertical lines - botimport.DebugLineShow(lines[2], bboxcorners[i], - bboxcorners[4+i], LINECOLOR_RED); - } //end for -} //end of the function AAS_ShowBoundingBox -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_ShowFace(int facenum) -{ - int i, color, edgenum; - aas_edge_t *edge; - aas_face_t *face; - aas_plane_t *plane; - vec3_t start, end; - - color = LINECOLOR_YELLOW; - //check if face number is in range - if (facenum >= aasworld.numfaces) - { - botimport.Print(PRT_ERROR, "facenum %d out of range\n", facenum); - } //end if - face = &aasworld.faces[facenum]; - //walk through the edges of the face - for (i = 0; i < face->numedges; i++) - { - //edge number - edgenum = abs(aasworld.edgeindex[face->firstedge + i]); - //check if edge number is in range - if (edgenum >= aasworld.numedges) - { - botimport.Print(PRT_ERROR, "edgenum %d out of range\n", edgenum); - } //end if - edge = &aasworld.edges[edgenum]; - if (color == LINECOLOR_RED) color = LINECOLOR_GREEN; - else if (color == LINECOLOR_GREEN) color = LINECOLOR_BLUE; - else if (color == LINECOLOR_BLUE) color = LINECOLOR_YELLOW; - else color = LINECOLOR_RED; - AAS_DebugLine(aasworld.vertexes[edge->v[0]], - aasworld.vertexes[edge->v[1]], - color); - } //end for - plane = &aasworld.planes[face->planenum]; - edgenum = abs(aasworld.edgeindex[face->firstedge]); - edge = &aasworld.edges[edgenum]; - VectorCopy(aasworld.vertexes[edge->v[0]], start); - VectorMA(start, 20, plane->normal, end); - AAS_DebugLine(start, end, LINECOLOR_RED); -} //end of the function AAS_ShowFace -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_ShowFacePolygon(int facenum, int color, int flip) -{ - int i, edgenum, numpoints; - vec3_t points[128]; - aas_edge_t *edge; - aas_face_t *face; - - //check if face number is in range - if (facenum >= aasworld.numfaces) - { - botimport.Print(PRT_ERROR, "facenum %d out of range\n", facenum); - } //end if - face = &aasworld.faces[facenum]; - //walk through the edges of the face - numpoints = 0; - if (flip) - { - for (i = face->numedges-1; i >= 0; i--) - { - //edge number - edgenum = aasworld.edgeindex[face->firstedge + i]; - edge = &aasworld.edges[abs(edgenum)]; - VectorCopy(aasworld.vertexes[edge->v[edgenum < 0]], points[numpoints]); - numpoints++; - } //end for - } //end if - else - { - for (i = 0; i < face->numedges; i++) - { - //edge number - edgenum = aasworld.edgeindex[face->firstedge + i]; - edge = &aasworld.edges[abs(edgenum)]; - VectorCopy(aasworld.vertexes[edge->v[edgenum < 0]], points[numpoints]); - numpoints++; - } //end for - } //end else - AAS_ShowPolygon(color, numpoints, points); -} //end of the function AAS_ShowFacePolygon -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_ShowArea(int areanum, int groundfacesonly) -{ - int areaedges[MAX_DEBUGLINES]; - int numareaedges, i, j, n, color = 0, line; - int facenum, edgenum; - aas_area_t *area; - aas_face_t *face; - aas_edge_t *edge; - - // - numareaedges = 0; - // - if (areanum < 0 || areanum >= aasworld.numareas) - { - botimport.Print(PRT_ERROR, "area %d out of range [0, %d]\n", - areanum, aasworld.numareas); - return; - } //end if - //pointer to the convex area - area = &aasworld.areas[areanum]; - //walk through the faces of the area - for (i = 0; i < area->numfaces; i++) - { - facenum = abs(aasworld.faceindex[area->firstface + i]); - //check if face number is in range - if (facenum >= aasworld.numfaces) - { - botimport.Print(PRT_ERROR, "facenum %d out of range\n", facenum); - } //end if - face = &aasworld.faces[facenum]; - //ground faces only - if (groundfacesonly) - { - if (!(face->faceflags & (FACE_GROUND | FACE_LADDER))) continue; - } //end if - //walk through the edges of the face - for (j = 0; j < face->numedges; j++) - { - //edge number - edgenum = abs(aasworld.edgeindex[face->firstedge + j]); - //check if edge number is in range - if (edgenum >= aasworld.numedges) - { - botimport.Print(PRT_ERROR, "edgenum %d out of range\n", edgenum); - } //end if - //check if the edge is stored already - for (n = 0; n < numareaedges; n++) - { - if (areaedges[n] == edgenum) break; - } //end for - if (n == numareaedges && numareaedges < MAX_DEBUGLINES) - { - areaedges[numareaedges++] = edgenum; - } //end if - } //end for - //AAS_ShowFace(facenum); - } //end for - //draw all the edges - for (n = 0; n < numareaedges; n++) - { - for (line = 0; line < MAX_DEBUGLINES; line++) - { - if (!debuglines[line]) - { - debuglines[line] = botimport.DebugLineCreate(); - debuglinevisible[line] = qfalse; - numdebuglines++; - } //end if - if (!debuglinevisible[line]) - { - break; - } //end else - } //end for - if (line >= MAX_DEBUGLINES) return; - edge = &aasworld.edges[areaedges[n]]; - if (color == LINECOLOR_RED) color = LINECOLOR_BLUE; - else if (color == LINECOLOR_BLUE) color = LINECOLOR_GREEN; - else if (color == LINECOLOR_GREEN) color = LINECOLOR_YELLOW; - else color = LINECOLOR_RED; - botimport.DebugLineShow(debuglines[line], - aasworld.vertexes[edge->v[0]], - aasworld.vertexes[edge->v[1]], - color); - debuglinevisible[line] = qtrue; - } //end for*/ -} //end of the function AAS_ShowArea -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_ShowAreaPolygons(int areanum, int color, int groundfacesonly) -{ - int i, facenum; - aas_area_t *area; - aas_face_t *face; - - // - if (areanum < 0 || areanum >= aasworld.numareas) - { - botimport.Print(PRT_ERROR, "area %d out of range [0, %d]\n", - areanum, aasworld.numareas); - return; - } //end if - //pointer to the convex area - area = &aasworld.areas[areanum]; - //walk through the faces of the area - for (i = 0; i < area->numfaces; i++) - { - facenum = abs(aasworld.faceindex[area->firstface + i]); - //check if face number is in range - if (facenum >= aasworld.numfaces) - { - botimport.Print(PRT_ERROR, "facenum %d out of range\n", facenum); - } //end if - face = &aasworld.faces[facenum]; - //ground faces only - if (groundfacesonly) - { - if (!(face->faceflags & (FACE_GROUND | FACE_LADDER))) continue; - } //end if - AAS_ShowFacePolygon(facenum, color, face->frontarea != areanum); - } //end for -} //end of the function AAS_ShowAreaPolygons -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_DrawCross(vec3_t origin, float size, int color) -{ - int i; - vec3_t start, end; - - for (i = 0; i < 3; i++) - { - VectorCopy(origin, start); - start[i] += size; - VectorCopy(origin, end); - end[i] -= size; - AAS_DebugLine(start, end, color); - } //end for -} //end of the function AAS_DrawCross -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_PrintTravelType(int traveltype) -{ -#ifdef DEBUG - char *str; - // - switch(traveltype & TRAVELTYPE_MASK) - { - case TRAVEL_INVALID: str = "TRAVEL_INVALID"; break; - case TRAVEL_WALK: str = "TRAVEL_WALK"; break; - case TRAVEL_CROUCH: str = "TRAVEL_CROUCH"; break; - case TRAVEL_BARRIERJUMP: str = "TRAVEL_BARRIERJUMP"; break; - case TRAVEL_JUMP: str = "TRAVEL_JUMP"; break; - case TRAVEL_LADDER: str = "TRAVEL_LADDER"; break; - case TRAVEL_WALKOFFLEDGE: str = "TRAVEL_WALKOFFLEDGE"; break; - case TRAVEL_SWIM: str = "TRAVEL_SWIM"; break; - case TRAVEL_WATERJUMP: str = "TRAVEL_WATERJUMP"; break; - case TRAVEL_TELEPORT: str = "TRAVEL_TELEPORT"; break; - case TRAVEL_ELEVATOR: str = "TRAVEL_ELEVATOR"; break; - case TRAVEL_ROCKETJUMP: str = "TRAVEL_ROCKETJUMP"; break; - case TRAVEL_BFGJUMP: str = "TRAVEL_BFGJUMP"; break; - case TRAVEL_GRAPPLEHOOK: str = "TRAVEL_GRAPPLEHOOK"; break; - case TRAVEL_JUMPPAD: str = "TRAVEL_JUMPPAD"; break; - case TRAVEL_FUNCBOB: str = "TRAVEL_FUNCBOB"; break; - default: str = "UNKNOWN TRAVEL TYPE"; break; - } //end switch - botimport.Print(PRT_MESSAGE, "%s", str); -#endif -} //end of the function AAS_PrintTravelType -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_DrawArrow(vec3_t start, vec3_t end, int linecolor, int arrowcolor) -{ - vec3_t dir, cross, p1, p2, up = {0, 0, 1}; - float dot; - - VectorSubtract(end, start, dir); - VectorNormalize(dir); - dot = DotProduct(dir, up); - if (dot > 0.99 || dot < -0.99) VectorSet(cross, 1, 0, 0); - else CrossProduct(dir, up, cross); - - VectorMA(end, -6, dir, p1); - VectorCopy(p1, p2); - VectorMA(p1, 6, cross, p1); - VectorMA(p2, -6, cross, p2); - - AAS_DebugLine(start, end, linecolor); - AAS_DebugLine(p1, end, arrowcolor); - AAS_DebugLine(p2, end, arrowcolor); -} //end of the function AAS_DrawArrow -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_ShowReachability(aas_reachability_t *reach) -{ - vec3_t dir, cmdmove, velocity; - float speed, zvel; - aas_clientmove_t move; - - AAS_ShowAreaPolygons(reach->areanum, 5, qtrue); - //AAS_ShowArea(reach->areanum, qtrue); - AAS_DrawArrow(reach->start, reach->end, LINECOLOR_BLUE, LINECOLOR_YELLOW); - // - if ((reach->traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMP || - (reach->traveltype & TRAVELTYPE_MASK) == TRAVEL_WALKOFFLEDGE) - { - AAS_HorizontalVelocityForJump(aassettings.phys_jumpvel, reach->start, reach->end, &speed); - // - VectorSubtract(reach->end, reach->start, dir); - dir[2] = 0; - VectorNormalize(dir); - //set the velocity - VectorScale(dir, speed, velocity); - //set the command movement - VectorClear(cmdmove); - cmdmove[2] = aassettings.phys_jumpvel; - // - AAS_PredictClientMovement(&move, -1, reach->start, PRESENCE_NORMAL, qtrue, - velocity, cmdmove, 3, 30, 0.1f, - SE_HITGROUND|SE_ENTERWATER|SE_ENTERSLIME| - SE_ENTERLAVA|SE_HITGROUNDDAMAGE, 0, qtrue); - // - if ((reach->traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMP) - { - AAS_JumpReachRunStart(reach, dir); - AAS_DrawCross(dir, 4, LINECOLOR_BLUE); - } //end if - } //end if - else if ((reach->traveltype & TRAVELTYPE_MASK) == TRAVEL_ROCKETJUMP) - { - zvel = AAS_RocketJumpZVelocity(reach->start); - AAS_HorizontalVelocityForJump(zvel, reach->start, reach->end, &speed); - // - VectorSubtract(reach->end, reach->start, dir); - dir[2] = 0; - VectorNormalize(dir); - //get command movement - VectorScale(dir, speed, cmdmove); - VectorSet(velocity, 0, 0, zvel); - // - AAS_PredictClientMovement(&move, -1, reach->start, PRESENCE_NORMAL, qtrue, - velocity, cmdmove, 30, 30, 0.1f, - SE_ENTERWATER|SE_ENTERSLIME| - SE_ENTERLAVA|SE_HITGROUNDDAMAGE| - SE_TOUCHJUMPPAD|SE_HITGROUNDAREA, reach->areanum, qtrue); - } //end else if - else if ((reach->traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMPPAD) - { - VectorSet(cmdmove, 0, 0, 0); - // - VectorSubtract(reach->end, reach->start, dir); - dir[2] = 0; - VectorNormalize(dir); - //set the velocity - //NOTE: the edgenum is the horizontal velocity - VectorScale(dir, reach->edgenum, velocity); - //NOTE: the facenum is the Z velocity - velocity[2] = reach->facenum; - // - AAS_PredictClientMovement(&move, -1, reach->start, PRESENCE_NORMAL, qtrue, - velocity, cmdmove, 30, 30, 0.1f, - SE_ENTERWATER|SE_ENTERSLIME| - SE_ENTERLAVA|SE_HITGROUNDDAMAGE| - SE_TOUCHJUMPPAD|SE_HITGROUNDAREA, reach->areanum, qtrue); - } //end else if -} //end of the function AAS_ShowReachability -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_ShowReachableAreas(int areanum) -{ - aas_areasettings_t *settings; - static aas_reachability_t reach; - static int index, lastareanum; - static float lasttime; - - if (areanum != lastareanum) - { - index = 0; - lastareanum = areanum; - } //end if - settings = &aasworld.areasettings[areanum]; - // - if (!settings->numreachableareas) return; - // - if (index >= settings->numreachableareas) index = 0; - // - if (AAS_Time() - lasttime > 1.5) - { - Com_Memcpy(&reach, &aasworld.reachability[settings->firstreachablearea + index], sizeof(aas_reachability_t)); - index++; - lasttime = AAS_Time(); - AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK); - botimport.Print(PRT_MESSAGE, "\n"); - } //end if - AAS_ShowReachability(&reach); -} //end of the function ShowReachableAreas - -void AAS_FloodAreas_r(int areanum, int cluster, int *done) -{ - int nextareanum, i, facenum; - aas_area_t *area; - aas_face_t *face; - aas_areasettings_t *settings; - aas_reachability_t *reach; - - AAS_ShowAreaPolygons(areanum, 1, qtrue); - //pointer to the convex area - area = &aasworld.areas[areanum]; - settings = &aasworld.areasettings[areanum]; - //walk through the faces of the area - for (i = 0; i < area->numfaces; i++) - { - facenum = abs(aasworld.faceindex[area->firstface + i]); - face = &aasworld.faces[facenum]; - if (face->frontarea == areanum) - nextareanum = face->backarea; - else - nextareanum = face->frontarea; - if (!nextareanum) - continue; - if (done[nextareanum]) - continue; - done[nextareanum] = qtrue; - if (aasworld.areasettings[nextareanum].contents & AREACONTENTS_VIEWPORTAL) - continue; - if (AAS_AreaCluster(nextareanum) != cluster) - continue; - AAS_FloodAreas_r(nextareanum, cluster, done); - } //end for - // - for (i = 0; i < settings->numreachableareas; i++) - { - reach = &aasworld.reachability[settings->firstreachablearea + i]; - nextareanum = reach->areanum; - if (!nextareanum) - continue; - if (done[nextareanum]) - continue; - done[nextareanum] = qtrue; - if (aasworld.areasettings[nextareanum].contents & AREACONTENTS_VIEWPORTAL) - continue; - if (AAS_AreaCluster(nextareanum) != cluster) - continue; - /* - if ((reach->traveltype & TRAVELTYPE_MASK) == TRAVEL_WALKOFFLEDGE) - { - AAS_DebugLine(reach->start, reach->end, 1); - } - */ - AAS_FloodAreas_r(nextareanum, cluster, done); - } -} - -void AAS_FloodAreas(vec3_t origin) -{ - int areanum, cluster, *done; - - done = (int *) GetClearedMemory(aasworld.numareas * sizeof(int)); - areanum = AAS_PointAreaNum(origin); - cluster = AAS_AreaCluster(areanum); - AAS_FloodAreas_r(areanum, cluster, done); -} diff --git a/src/botlib/be_aas_debug.h b/src/botlib/be_aas_debug.h deleted file mode 100644 index 438b95cf..00000000 --- a/src/botlib/be_aas_debug.h +++ /dev/null @@ -1,63 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_aas_debug.h - * - * desc: AAS - * - * $Archive: /source/code/botlib/be_aas_debug.h $ - * - *****************************************************************************/ - -//clear the shown debug lines -void AAS_ClearShownDebugLines(void); -// -void AAS_ClearShownPolygons(void); -//show a debug line -void AAS_DebugLine(vec3_t start, vec3_t end, int color); -//show a permenent line -void AAS_PermanentLine(vec3_t start, vec3_t end, int color); -//show a permanent cross -void AAS_DrawPermanentCross(vec3_t origin, float size, int color); -//draw a cross in the plane -void AAS_DrawPlaneCross(vec3_t point, vec3_t normal, float dist, int type, int color); -//show a bounding box -void AAS_ShowBoundingBox(vec3_t origin, vec3_t mins, vec3_t maxs); -//show a face -void AAS_ShowFace(int facenum); -//show an area -void AAS_ShowArea(int areanum, int groundfacesonly); -// -void AAS_ShowAreaPolygons(int areanum, int color, int groundfacesonly); -//draw a cros -void AAS_DrawCross(vec3_t origin, float size, int color); -//print the travel type -void AAS_PrintTravelType(int traveltype); -//draw an arrow -void AAS_DrawArrow(vec3_t start, vec3_t end, int linecolor, int arrowcolor); -//visualize the given reachability -void AAS_ShowReachability(struct aas_reachability_s *reach); -//show the reachable areas from the given area -void AAS_ShowReachableAreas(int areanum); - diff --git a/src/botlib/be_aas_def.h b/src/botlib/be_aas_def.h deleted file mode 100644 index a0558b58..00000000 --- a/src/botlib/be_aas_def.h +++ /dev/null @@ -1,307 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_aas_def.h - * - * desc: AAS - * - * $Archive: /source/code/botlib/be_aas_def.h $ - * - *****************************************************************************/ - -//debugging on -#define AAS_DEBUG - -#define MAX_CLIENTS 64 -#define MAX_MODELS 256 // these are sent over the net as 8 bits -#define MAX_SOUNDS 256 // so they cannot be blindly increased -#define MAX_CONFIGSTRINGS 1024 - -#define CS_SCORES 32 -#define CS_MODELS (CS_SCORES+MAX_CLIENTS) -#define CS_SOUNDS (CS_MODELS+MAX_MODELS) - -#define DF_AASENTNUMBER(x) (x - aasworld.entities) -#define DF_NUMBERAASENT(x) (&aasworld.entities[x]) -#define DF_AASENTCLIENT(x) (x - aasworld.entities - 1) -#define DF_CLIENTAASENT(x) (&aasworld.entities[x + 1]) - -#ifndef MAX_PATH - #define MAX_PATH MAX_QPATH -#endif - -//string index (for model, sound and image index) -typedef struct aas_stringindex_s -{ - int numindexes; - char **index; -} aas_stringindex_t; - -//structure to link entities to areas and areas to entities -typedef struct aas_link_s -{ - int entnum; - int areanum; - struct aas_link_s *next_ent, *prev_ent; - struct aas_link_s *next_area, *prev_area; -} aas_link_t; - -//structure to link entities to leaves and leaves to entities -typedef struct bsp_link_s -{ - int entnum; - int leafnum; - struct bsp_link_s *next_ent, *prev_ent; - struct bsp_link_s *next_leaf, *prev_leaf; -} bsp_link_t; - -typedef struct bsp_entdata_s -{ - vec3_t origin; - vec3_t angles; - vec3_t absmins; - vec3_t absmaxs; - int solid; - int modelnum; -} bsp_entdata_t; - -//entity -typedef struct aas_entity_s -{ - //entity info - aas_entityinfo_t i; - //links into the AAS areas - aas_link_t *areas; - //links into the BSP leaves - bsp_link_t *leaves; -} aas_entity_t; - -typedef struct aas_settings_s -{ - vec3_t phys_gravitydirection; - float phys_friction; - float phys_stopspeed; - float phys_gravity; - float phys_waterfriction; - float phys_watergravity; - float phys_maxvelocity; - float phys_maxwalkvelocity; - float phys_maxcrouchvelocity; - float phys_maxswimvelocity; - float phys_walkaccelerate; - float phys_airaccelerate; - float phys_swimaccelerate; - float phys_maxstep; - float phys_maxsteepness; - float phys_maxwaterjump; - float phys_maxbarrier; - float phys_jumpvel; - float phys_falldelta5; - float phys_falldelta10; - float rs_waterjump; - float rs_teleport; - float rs_barrierjump; - float rs_startcrouch; - float rs_startgrapple; - float rs_startwalkoffledge; - float rs_startjump; - float rs_rocketjump; - float rs_bfgjump; - float rs_jumppad; - float rs_aircontrolledjumppad; - float rs_funcbob; - float rs_startelevator; - float rs_falldamage5; - float rs_falldamage10; - float rs_maxfallheight; - float rs_maxjumpfallheight; -} aas_settings_t; - -#define CACHETYPE_PORTAL 0 -#define CACHETYPE_AREA 1 - -//routing cache -typedef struct aas_routingcache_s -{ - byte type; //portal or area cache - float time; //last time accessed or updated - int size; //size of the routing cache - int cluster; //cluster the cache is for - int areanum; //area the cache is created for - vec3_t origin; //origin within the area - float starttraveltime; //travel time to start with - int travelflags; //combinations of the travel flags - struct aas_routingcache_s *prev, *next; - struct aas_routingcache_s *time_prev, *time_next; - unsigned char *reachabilities; //reachabilities used for routing - unsigned short int traveltimes[1]; //travel time for every area (variable sized) -} aas_routingcache_t; - -//fields for the routing algorithm -typedef struct aas_routingupdate_s -{ - int cluster; - int areanum; //area number of the update - vec3_t start; //start point the area was entered - unsigned short int tmptraveltime; //temporary travel time - unsigned short int *areatraveltimes; //travel times within the area - qboolean inlist; //true if the update is in the list - struct aas_routingupdate_s *next; - struct aas_routingupdate_s *prev; -} aas_routingupdate_t; - -//reversed reachability link -typedef struct aas_reversedlink_s -{ - int linknum; //the aas_areareachability_t - int areanum; //reachable from this area - struct aas_reversedlink_s *next; //next link -} aas_reversedlink_t; - -//reversed area reachability -typedef struct aas_reversedreachability_s -{ - int numlinks; - aas_reversedlink_t *first; -} aas_reversedreachability_t; - -//areas a reachability goes through -typedef struct aas_reachabilityareas_s -{ - int firstarea, numareas; -} aas_reachabilityareas_t; - -typedef struct aas_s -{ - int loaded; //true when an AAS file is loaded - int initialized; //true when AAS has been initialized - int savefile; //set true when file should be saved - int bspchecksum; - //current time - float time; - int numframes; - //name of the aas file - char filename[MAX_PATH]; - char mapname[MAX_PATH]; - //bounding boxes - int numbboxes; - aas_bbox_t *bboxes; - //vertexes - int numvertexes; - aas_vertex_t *vertexes; - //planes - int numplanes; - aas_plane_t *planes; - //edges - int numedges; - aas_edge_t *edges; - //edge index - int edgeindexsize; - aas_edgeindex_t *edgeindex; - //faces - int numfaces; - aas_face_t *faces; - //face index - int faceindexsize; - aas_faceindex_t *faceindex; - //convex areas - int numareas; - aas_area_t *areas; - //convex area settings - int numareasettings; - aas_areasettings_t *areasettings; - //reachablity list - int reachabilitysize; - aas_reachability_t *reachability; - //nodes of the bsp tree - int numnodes; - aas_node_t *nodes; - //cluster portals - int numportals; - aas_portal_t *portals; - //cluster portal index - int portalindexsize; - aas_portalindex_t *portalindex; - //clusters - int numclusters; - aas_cluster_t *clusters; - // - int numreachabilityareas; - float reachabilitytime; - //enities linked in the areas - aas_link_t *linkheap; //heap with link structures - int linkheapsize; //size of the link heap - aas_link_t *freelinks; //first free link - aas_link_t **arealinkedentities; //entities linked into areas - //entities - int maxentities; - int maxclients; - aas_entity_t *entities; - //string indexes - char *configstrings[MAX_CONFIGSTRINGS]; - int indexessetup; - //index to retrieve travel flag for a travel type - int travelflagfortype[MAX_TRAVELTYPES]; - //travel flags for each area based on contents - int *areacontentstravelflags; - //routing update - aas_routingupdate_t *areaupdate; - aas_routingupdate_t *portalupdate; - //number of routing updates during a frame (reset every frame) - int frameroutingupdates; - //reversed reachability links - aas_reversedreachability_t *reversedreachability; - //travel times within the areas - unsigned short ***areatraveltimes; - //array of size numclusters with cluster cache - aas_routingcache_t ***clusterareacache; - aas_routingcache_t **portalcache; - //cache list sorted on time - aas_routingcache_t *oldestcache; // start of cache list sorted on time - aas_routingcache_t *newestcache; // end of cache list sorted on time - //maximum travel time through portal areas - int *portalmaxtraveltimes; - //areas the reachabilities go through - int *reachabilityareaindex; - aas_reachabilityareas_t *reachabilityareas; -} aas_t; - -#define AASINTERN - -#ifndef BSPCINCLUDE - -#include "be_aas_main.h" -#include "be_aas_entity.h" -#include "be_aas_sample.h" -#include "be_aas_cluster.h" -#include "be_aas_reach.h" -#include "be_aas_route.h" -#include "be_aas_routealt.h" -#include "be_aas_debug.h" -#include "be_aas_file.h" -#include "be_aas_optimize.h" -#include "be_aas_bsp.h" -#include "be_aas_move.h" - -#endif //BSPCINCLUDE diff --git a/src/botlib/be_aas_entity.c b/src/botlib/be_aas_entity.c deleted file mode 100644 index e36f4716..00000000 --- a/src/botlib/be_aas_entity.c +++ /dev/null @@ -1,438 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_aas_entity.c - * - * desc: AAS entities - * - * $Archive: /MissionPack/code/botlib/be_aas_entity.c $ - * - *****************************************************************************/ - -#include "../qcommon/q_shared.h" -#include "l_memory.h" -#include "l_script.h" -#include "l_precomp.h" -#include "l_struct.h" -#include "l_utils.h" -#include "l_log.h" -#include "aasfile.h" -#include "botlib.h" -#include "be_aas.h" -#include "be_aas_funcs.h" -#include "be_interface.h" -#include "be_aas_def.h" - -#define MASK_SOLID CONTENTS_PLAYERCLIP - -//FIXME: these might change -enum { - ET_GENERAL, - ET_PLAYER, - ET_ITEM, - ET_MISSILE, - ET_MOVER -}; - -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_UpdateEntity(int entnum, bot_entitystate_t *state) -{ - int relink; - aas_entity_t *ent; - vec3_t absmins, absmaxs; - - if (!aasworld.loaded) - { - botimport.Print(PRT_MESSAGE, "AAS_UpdateEntity: not loaded\n"); - return BLERR_NOAASFILE; - } //end if - - ent = &aasworld.entities[entnum]; - - if (!state) { - //unlink the entity - AAS_UnlinkFromAreas(ent->areas); - //unlink the entity from the BSP leaves - AAS_UnlinkFromBSPLeaves(ent->leaves); - // - ent->areas = NULL; - // - ent->leaves = NULL; - return BLERR_NOERROR; - } - - ent->i.update_time = AAS_Time() - ent->i.ltime; - ent->i.type = state->type; - ent->i.flags = state->flags; - ent->i.ltime = AAS_Time(); - VectorCopy(ent->i.origin, ent->i.lastvisorigin); - VectorCopy(state->old_origin, ent->i.old_origin); - ent->i.solid = state->solid; - ent->i.groundent = state->groundent; - ent->i.modelindex = state->modelindex; - ent->i.modelindex2 = state->modelindex2; - ent->i.frame = state->frame; - ent->i.event = state->event; - ent->i.eventParm = state->eventParm; - ent->i.powerups = state->powerups; - ent->i.weapon = state->weapon; - ent->i.legsAnim = state->legsAnim; - ent->i.torsoAnim = state->torsoAnim; - //number of the entity - ent->i.number = entnum; - //updated so set valid flag - ent->i.valid = qtrue; - //link everything the first frame - if (aasworld.numframes == 1) relink = qtrue; - else relink = qfalse; - // - if (ent->i.solid == SOLID_BSP) - { - //if the angles of the model changed - if (!VectorCompare(state->angles, ent->i.angles)) - { - VectorCopy(state->angles, ent->i.angles); - relink = qtrue; - } //end if - //get the mins and maxs of the model - //FIXME: rotate mins and maxs - AAS_BSPModelMinsMaxsOrigin(ent->i.modelindex, ent->i.angles, ent->i.mins, ent->i.maxs, NULL); - } //end if - else if (ent->i.solid == SOLID_BBOX) - { - //if the bounding box size changed - if (!VectorCompare(state->mins, ent->i.mins) || - !VectorCompare(state->maxs, ent->i.maxs)) - { - VectorCopy(state->mins, ent->i.mins); - VectorCopy(state->maxs, ent->i.maxs); - relink = qtrue; - } //end if - VectorCopy(state->angles, ent->i.angles); - } //end if - //if the origin changed - if (!VectorCompare(state->origin, ent->i.origin)) - { - VectorCopy(state->origin, ent->i.origin); - relink = qtrue; - } //end if - //if the entity should be relinked - if (relink) - { - //don't link the world model - if (entnum != ENTITYNUM_WORLD) - { - //absolute mins and maxs - VectorAdd(ent->i.mins, ent->i.origin, absmins); - VectorAdd(ent->i.maxs, ent->i.origin, absmaxs); - //unlink the entity - AAS_UnlinkFromAreas(ent->areas); - //relink the entity to the AAS areas (use the larges bbox) - ent->areas = AAS_LinkEntityClientBBox(absmins, absmaxs, entnum, PRESENCE_NORMAL); - //unlink the entity from the BSP leaves - AAS_UnlinkFromBSPLeaves(ent->leaves); - //link the entity to the world BSP tree - ent->leaves = AAS_BSPLinkEntity(absmins, absmaxs, entnum, 0); - } //end if - } //end if - return BLERR_NOERROR; -} //end of the function AAS_UpdateEntity -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_EntityInfo(int entnum, aas_entityinfo_t *info) -{ - if (!aasworld.initialized) - { - botimport.Print(PRT_FATAL, "AAS_EntityInfo: aasworld not initialized\n"); - Com_Memset(info, 0, sizeof(aas_entityinfo_t)); - return; - } //end if - - if (entnum < 0 || entnum >= aasworld.maxentities) - { - botimport.Print(PRT_FATAL, "AAS_EntityInfo: entnum %d out of range\n", entnum); - Com_Memset(info, 0, sizeof(aas_entityinfo_t)); - return; - } //end if - - Com_Memcpy(info, &aasworld.entities[entnum].i, sizeof(aas_entityinfo_t)); -} //end of the function AAS_EntityInfo -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_EntityOrigin(int entnum, vec3_t origin) -{ - if (entnum < 0 || entnum >= aasworld.maxentities) - { - botimport.Print(PRT_FATAL, "AAS_EntityOrigin: entnum %d out of range\n", entnum); - VectorClear(origin); - return; - } //end if - - VectorCopy(aasworld.entities[entnum].i.origin, origin); -} //end of the function AAS_EntityOrigin -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_EntityModelindex(int entnum) -{ - if (entnum < 0 || entnum >= aasworld.maxentities) - { - botimport.Print(PRT_FATAL, "AAS_EntityModelindex: entnum %d out of range\n", entnum); - return 0; - } //end if - return aasworld.entities[entnum].i.modelindex; -} //end of the function AAS_EntityModelindex -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_EntityType(int entnum) -{ - if (!aasworld.initialized) return 0; - - if (entnum < 0 || entnum >= aasworld.maxentities) - { - botimport.Print(PRT_FATAL, "AAS_EntityType: entnum %d out of range\n", entnum); - return 0; - } //end if - return aasworld.entities[entnum].i.type; -} //end of the AAS_EntityType -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_EntityModelNum(int entnum) -{ - if (!aasworld.initialized) return 0; - - if (entnum < 0 || entnum >= aasworld.maxentities) - { - botimport.Print(PRT_FATAL, "AAS_EntityModelNum: entnum %d out of range\n", entnum); - return 0; - } //end if - return aasworld.entities[entnum].i.modelindex; -} //end of the function AAS_EntityModelNum -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_OriginOfMoverWithModelNum(int modelnum, vec3_t origin) -{ - int i; - aas_entity_t *ent; - - for (i = 0; i < aasworld.maxentities; i++) - { - ent = &aasworld.entities[i]; - if (ent->i.type == ET_MOVER) - { - if (ent->i.modelindex == modelnum) - { - VectorCopy(ent->i.origin, origin); - return qtrue; - } //end if - } //end if - } //end for - return qfalse; -} //end of the function AAS_OriginOfMoverWithModelNum -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_EntitySize(int entnum, vec3_t mins, vec3_t maxs) -{ - aas_entity_t *ent; - - if (!aasworld.initialized) return; - - if (entnum < 0 || entnum >= aasworld.maxentities) - { - botimport.Print(PRT_FATAL, "AAS_EntitySize: entnum %d out of range\n", entnum); - return; - } //end if - - ent = &aasworld.entities[entnum]; - VectorCopy(ent->i.mins, mins); - VectorCopy(ent->i.maxs, maxs); -} //end of the function AAS_EntitySize -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_EntityBSPData(int entnum, bsp_entdata_t *entdata) -{ - aas_entity_t *ent; - - ent = &aasworld.entities[entnum]; - VectorCopy(ent->i.origin, entdata->origin); - VectorCopy(ent->i.angles, entdata->angles); - VectorAdd(ent->i.origin, ent->i.mins, entdata->absmins); - VectorAdd(ent->i.origin, ent->i.maxs, entdata->absmaxs); - entdata->solid = ent->i.solid; - entdata->modelnum = ent->i.modelindex - 1; -} //end of the function AAS_EntityBSPData -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_ResetEntityLinks(void) -{ - int i; - for (i = 0; i < aasworld.maxentities; i++) - { - aasworld.entities[i].areas = NULL; - aasworld.entities[i].leaves = NULL; - } //end for -} //end of the function AAS_ResetEntityLinks -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_InvalidateEntities(void) -{ - int i; - for (i = 0; i < aasworld.maxentities; i++) - { - aasworld.entities[i].i.valid = qfalse; - aasworld.entities[i].i.number = i; - } //end for -} //end of the function AAS_InvalidateEntities -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_UnlinkInvalidEntities(void) -{ - int i; - aas_entity_t *ent; - - for (i = 0; i < aasworld.maxentities; i++) - { - ent = &aasworld.entities[i]; - if (!ent->i.valid) - { - AAS_UnlinkFromAreas( ent->areas ); - ent->areas = NULL; - AAS_UnlinkFromBSPLeaves( ent->leaves ); - ent->leaves = NULL; - } //end for - } //end for -} //end of the function AAS_UnlinkInvalidEntities -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_NearestEntity(vec3_t origin, int modelindex) -{ - int i, bestentnum; - float dist, bestdist; - aas_entity_t *ent; - vec3_t dir; - - bestentnum = 0; - bestdist = 99999; - for (i = 0; i < aasworld.maxentities; i++) - { - ent = &aasworld.entities[i]; - if (ent->i.modelindex != modelindex) continue; - VectorSubtract(ent->i.origin, origin, dir); - if (abs(dir[0]) < 40) - { - if (abs(dir[1]) < 40) - { - dist = VectorLength(dir); - if (dist < bestdist) - { - bestdist = dist; - bestentnum = i; - } //end if - } //end if - } //end if - } //end for - return bestentnum; -} //end of the function AAS_NearestEntity -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_BestReachableEntityArea(int entnum) -{ - aas_entity_t *ent; - - ent = &aasworld.entities[entnum]; - return AAS_BestReachableLinkArea(ent->areas); -} //end of the function AAS_BestReachableEntityArea -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_NextEntity(int entnum) -{ - if (!aasworld.loaded) return 0; - - if (entnum < 0) entnum = -1; - while(++entnum < aasworld.maxentities) - { - if (aasworld.entities[entnum].i.valid) return entnum; - } //end while - return 0; -} //end of the function AAS_NextEntity diff --git a/src/botlib/be_aas_entity.h b/src/botlib/be_aas_entity.h deleted file mode 100644 index 89b7d1c3..00000000 --- a/src/botlib/be_aas_entity.h +++ /dev/null @@ -1,64 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_aas_entity.h - * - * desc: AAS - * - * $Archive: /source/code/botlib/be_aas_entity.h $ - * - *****************************************************************************/ - -#ifdef AASINTERN -//invalidates all entity infos -void AAS_InvalidateEntities(void); -//unlink not updated entities -void AAS_UnlinkInvalidEntities(void); -//resets the entity AAS and BSP links (sets areas and leaves pointers to NULL) -void AAS_ResetEntityLinks(void); -//updates an entity -int AAS_UpdateEntity(int ent, bot_entitystate_t *state); -//gives the entity data used for collision detection -void AAS_EntityBSPData(int entnum, bsp_entdata_t *entdata); -#endif //AASINTERN - -//returns the size of the entity bounding box in mins and maxs -void AAS_EntitySize(int entnum, vec3_t mins, vec3_t maxs); -//returns the BSP model number of the entity -int AAS_EntityModelNum(int entnum); -//returns the origin of an entity with the given model number -int AAS_OriginOfMoverWithModelNum(int modelnum, vec3_t origin); -//returns the best reachable area the entity is situated in -int AAS_BestReachableEntityArea(int entnum); -//returns the info of the given entity -void AAS_EntityInfo(int entnum, aas_entityinfo_t *info); -//returns the next entity -int AAS_NextEntity(int entnum); -//returns the origin of the entity -void AAS_EntityOrigin(int entnum, vec3_t origin); -//returns the entity type -int AAS_EntityType(int entnum); -//returns the model index of the entity -int AAS_EntityModelindex(int entnum); - diff --git a/src/botlib/be_aas_file.c b/src/botlib/be_aas_file.c deleted file mode 100644 index 024081f4..00000000 --- a/src/botlib/be_aas_file.c +++ /dev/null @@ -1,583 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_aas_file.c - * - * desc: AAS file loading/writing - * - * $Archive: /MissionPack/code/botlib/be_aas_file.c $ - * - *****************************************************************************/ - -#include "../qcommon/q_shared.h" -#include "l_memory.h" -#include "l_script.h" -#include "l_precomp.h" -#include "l_struct.h" -#include "l_libvar.h" -#include "l_utils.h" -#include "aasfile.h" -#include "botlib.h" -#include "be_aas.h" -#include "be_aas_funcs.h" -#include "be_interface.h" -#include "be_aas_def.h" - -//#define AASFILEDEBUG - -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_SwapAASData(void) -{ - int i, j; - //bounding boxes - for (i = 0; i < aasworld.numbboxes; i++) - { - aasworld.bboxes[i].presencetype = LittleLong(aasworld.bboxes[i].presencetype); - aasworld.bboxes[i].flags = LittleLong(aasworld.bboxes[i].flags); - for (j = 0; j < 3; j++) - { - aasworld.bboxes[i].mins[j] = LittleLong(aasworld.bboxes[i].mins[j]); - aasworld.bboxes[i].maxs[j] = LittleLong(aasworld.bboxes[i].maxs[j]); - } //end for - } //end for - //vertexes - for (i = 0; i < aasworld.numvertexes; i++) - { - for (j = 0; j < 3; j++) - aasworld.vertexes[i][j] = LittleFloat(aasworld.vertexes[i][j]); - } //end for - //planes - for (i = 0; i < aasworld.numplanes; i++) - { - for (j = 0; j < 3; j++) - aasworld.planes[i].normal[j] = LittleFloat(aasworld.planes[i].normal[j]); - aasworld.planes[i].dist = LittleFloat(aasworld.planes[i].dist); - aasworld.planes[i].type = LittleLong(aasworld.planes[i].type); - } //end for - //edges - for (i = 0; i < aasworld.numedges; i++) - { - aasworld.edges[i].v[0] = LittleLong(aasworld.edges[i].v[0]); - aasworld.edges[i].v[1] = LittleLong(aasworld.edges[i].v[1]); - } //end for - //edgeindex - for (i = 0; i < aasworld.edgeindexsize; i++) - { - aasworld.edgeindex[i] = LittleLong(aasworld.edgeindex[i]); - } //end for - //faces - for (i = 0; i < aasworld.numfaces; i++) - { - aasworld.faces[i].planenum = LittleLong(aasworld.faces[i].planenum); - aasworld.faces[i].faceflags = LittleLong(aasworld.faces[i].faceflags); - aasworld.faces[i].numedges = LittleLong(aasworld.faces[i].numedges); - aasworld.faces[i].firstedge = LittleLong(aasworld.faces[i].firstedge); - aasworld.faces[i].frontarea = LittleLong(aasworld.faces[i].frontarea); - aasworld.faces[i].backarea = LittleLong(aasworld.faces[i].backarea); - } //end for - //face index - for (i = 0; i < aasworld.faceindexsize; i++) - { - aasworld.faceindex[i] = LittleLong(aasworld.faceindex[i]); - } //end for - //convex areas - for (i = 0; i < aasworld.numareas; i++) - { - aasworld.areas[i].areanum = LittleLong(aasworld.areas[i].areanum); - aasworld.areas[i].numfaces = LittleLong(aasworld.areas[i].numfaces); - aasworld.areas[i].firstface = LittleLong(aasworld.areas[i].firstface); - for (j = 0; j < 3; j++) - { - aasworld.areas[i].mins[j] = LittleFloat(aasworld.areas[i].mins[j]); - aasworld.areas[i].maxs[j] = LittleFloat(aasworld.areas[i].maxs[j]); - aasworld.areas[i].center[j] = LittleFloat(aasworld.areas[i].center[j]); - } //end for - } //end for - //area settings - for (i = 0; i < aasworld.numareasettings; i++) - { - aasworld.areasettings[i].contents = LittleLong(aasworld.areasettings[i].contents); - aasworld.areasettings[i].areaflags = LittleLong(aasworld.areasettings[i].areaflags); - aasworld.areasettings[i].presencetype = LittleLong(aasworld.areasettings[i].presencetype); - aasworld.areasettings[i].cluster = LittleLong(aasworld.areasettings[i].cluster); - aasworld.areasettings[i].clusterareanum = LittleLong(aasworld.areasettings[i].clusterareanum); - aasworld.areasettings[i].numreachableareas = LittleLong(aasworld.areasettings[i].numreachableareas); - aasworld.areasettings[i].firstreachablearea = LittleLong(aasworld.areasettings[i].firstreachablearea); - } //end for - //area reachability - for (i = 0; i < aasworld.reachabilitysize; i++) - { - aasworld.reachability[i].areanum = LittleLong(aasworld.reachability[i].areanum); - aasworld.reachability[i].facenum = LittleLong(aasworld.reachability[i].facenum); - aasworld.reachability[i].edgenum = LittleLong(aasworld.reachability[i].edgenum); - for (j = 0; j < 3; j++) - { - aasworld.reachability[i].start[j] = LittleFloat(aasworld.reachability[i].start[j]); - aasworld.reachability[i].end[j] = LittleFloat(aasworld.reachability[i].end[j]); - } //end for - aasworld.reachability[i].traveltype = LittleLong(aasworld.reachability[i].traveltype); - aasworld.reachability[i].traveltime = LittleShort(aasworld.reachability[i].traveltime); - } //end for - //nodes - for (i = 0; i < aasworld.numnodes; i++) - { - aasworld.nodes[i].planenum = LittleLong(aasworld.nodes[i].planenum); - aasworld.nodes[i].children[0] = LittleLong(aasworld.nodes[i].children[0]); - aasworld.nodes[i].children[1] = LittleLong(aasworld.nodes[i].children[1]); - } //end for - //cluster portals - for (i = 0; i < aasworld.numportals; i++) - { - aasworld.portals[i].areanum = LittleLong(aasworld.portals[i].areanum); - aasworld.portals[i].frontcluster = LittleLong(aasworld.portals[i].frontcluster); - aasworld.portals[i].backcluster = LittleLong(aasworld.portals[i].backcluster); - aasworld.portals[i].clusterareanum[0] = LittleLong(aasworld.portals[i].clusterareanum[0]); - aasworld.portals[i].clusterareanum[1] = LittleLong(aasworld.portals[i].clusterareanum[1]); - } //end for - //cluster portal index - for (i = 0; i < aasworld.portalindexsize; i++) - { - aasworld.portalindex[i] = LittleLong(aasworld.portalindex[i]); - } //end for - //cluster - for (i = 0; i < aasworld.numclusters; i++) - { - aasworld.clusters[i].numareas = LittleLong(aasworld.clusters[i].numareas); - aasworld.clusters[i].numreachabilityareas = LittleLong(aasworld.clusters[i].numreachabilityareas); - aasworld.clusters[i].numportals = LittleLong(aasworld.clusters[i].numportals); - aasworld.clusters[i].firstportal = LittleLong(aasworld.clusters[i].firstportal); - } //end for -} //end of the function AAS_SwapAASData -//=========================================================================== -// dump the current loaded aas file -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_DumpAASData(void) -{ - aasworld.numbboxes = 0; - if (aasworld.bboxes) FreeMemory(aasworld.bboxes); - aasworld.bboxes = NULL; - aasworld.numvertexes = 0; - if (aasworld.vertexes) FreeMemory(aasworld.vertexes); - aasworld.vertexes = NULL; - aasworld.numplanes = 0; - if (aasworld.planes) FreeMemory(aasworld.planes); - aasworld.planes = NULL; - aasworld.numedges = 0; - if (aasworld.edges) FreeMemory(aasworld.edges); - aasworld.edges = NULL; - aasworld.edgeindexsize = 0; - if (aasworld.edgeindex) FreeMemory(aasworld.edgeindex); - aasworld.edgeindex = NULL; - aasworld.numfaces = 0; - if (aasworld.faces) FreeMemory(aasworld.faces); - aasworld.faces = NULL; - aasworld.faceindexsize = 0; - if (aasworld.faceindex) FreeMemory(aasworld.faceindex); - aasworld.faceindex = NULL; - aasworld.numareas = 0; - if (aasworld.areas) FreeMemory(aasworld.areas); - aasworld.areas = NULL; - aasworld.numareasettings = 0; - if (aasworld.areasettings) FreeMemory(aasworld.areasettings); - aasworld.areasettings = NULL; - aasworld.reachabilitysize = 0; - if (aasworld.reachability) FreeMemory(aasworld.reachability); - aasworld.reachability = NULL; - aasworld.numnodes = 0; - if (aasworld.nodes) FreeMemory(aasworld.nodes); - aasworld.nodes = NULL; - aasworld.numportals = 0; - if (aasworld.portals) FreeMemory(aasworld.portals); - aasworld.portals = NULL; - aasworld.numportals = 0; - if (aasworld.portalindex) FreeMemory(aasworld.portalindex); - aasworld.portalindex = NULL; - aasworld.portalindexsize = 0; - if (aasworld.clusters) FreeMemory(aasworld.clusters); - aasworld.clusters = NULL; - aasworld.numclusters = 0; - // - aasworld.loaded = qfalse; - aasworld.initialized = qfalse; - aasworld.savefile = qfalse; -} //end of the function AAS_DumpAASData -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -#ifdef AASFILEDEBUG -void AAS_FileInfo(void) -{ - int i, n, optimized; - - botimport.Print(PRT_MESSAGE, "version = %d\n", AASVERSION); - botimport.Print(PRT_MESSAGE, "numvertexes = %d\n", aasworld.numvertexes); - botimport.Print(PRT_MESSAGE, "numplanes = %d\n", aasworld.numplanes); - botimport.Print(PRT_MESSAGE, "numedges = %d\n", aasworld.numedges); - botimport.Print(PRT_MESSAGE, "edgeindexsize = %d\n", aasworld.edgeindexsize); - botimport.Print(PRT_MESSAGE, "numfaces = %d\n", aasworld.numfaces); - botimport.Print(PRT_MESSAGE, "faceindexsize = %d\n", aasworld.faceindexsize); - botimport.Print(PRT_MESSAGE, "numareas = %d\n", aasworld.numareas); - botimport.Print(PRT_MESSAGE, "numareasettings = %d\n", aasworld.numareasettings); - botimport.Print(PRT_MESSAGE, "reachabilitysize = %d\n", aasworld.reachabilitysize); - botimport.Print(PRT_MESSAGE, "numnodes = %d\n", aasworld.numnodes); - botimport.Print(PRT_MESSAGE, "numportals = %d\n", aasworld.numportals); - botimport.Print(PRT_MESSAGE, "portalindexsize = %d\n", aasworld.portalindexsize); - botimport.Print(PRT_MESSAGE, "numclusters = %d\n", aasworld.numclusters); - // - for (n = 0, i = 0; i < aasworld.numareasettings; i++) - { - if (aasworld.areasettings[i].areaflags & AREA_GROUNDED) n++; - } //end for - botimport.Print(PRT_MESSAGE, "num grounded areas = %d\n", n); - // - botimport.Print(PRT_MESSAGE, "planes size %d bytes\n", aasworld.numplanes * sizeof(aas_plane_t)); - botimport.Print(PRT_MESSAGE, "areas size %d bytes\n", aasworld.numareas * sizeof(aas_area_t)); - botimport.Print(PRT_MESSAGE, "areasettings size %d bytes\n", aasworld.numareasettings * sizeof(aas_areasettings_t)); - botimport.Print(PRT_MESSAGE, "nodes size %d bytes\n", aasworld.numnodes * sizeof(aas_node_t)); - botimport.Print(PRT_MESSAGE, "reachability size %d bytes\n", aasworld.reachabilitysize * sizeof(aas_reachability_t)); - botimport.Print(PRT_MESSAGE, "portals size %d bytes\n", aasworld.numportals * sizeof(aas_portal_t)); - botimport.Print(PRT_MESSAGE, "clusters size %d bytes\n", aasworld.numclusters * sizeof(aas_cluster_t)); - - optimized = aasworld.numplanes * sizeof(aas_plane_t) + - aasworld.numareas * sizeof(aas_area_t) + - aasworld.numareasettings * sizeof(aas_areasettings_t) + - aasworld.numnodes * sizeof(aas_node_t) + - aasworld.reachabilitysize * sizeof(aas_reachability_t) + - aasworld.numportals * sizeof(aas_portal_t) + - aasworld.numclusters * sizeof(aas_cluster_t); - botimport.Print(PRT_MESSAGE, "optimzed size %d KB\n", optimized >> 10); -} //end of the function AAS_FileInfo -#endif //AASFILEDEBUG -//=========================================================================== -// allocate memory and read a lump of a AAS file -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -char *AAS_LoadAASLump(fileHandle_t fp, int offset, int length, int *lastoffset, int size) -{ - char *buf; - // - if (!length) - { - //just alloc a dummy - return (char *) GetClearedHunkMemory(size+1); - } //end if - //seek to the data - if (offset != *lastoffset) - { - botimport.Print(PRT_WARNING, "AAS file not sequentially read\n"); - if (botimport.FS_Seek(fp, offset, FS_SEEK_SET)) - { - AAS_Error("can't seek to aas lump\n"); - AAS_DumpAASData(); - botimport.FS_FCloseFile(fp); - return NULL; - } //end if - } //end if - //allocate memory - buf = (char *) GetClearedHunkMemory(length+1); - //read the data - if (length) - { - botimport.FS_Read(buf, length, fp ); - *lastoffset += length; - } //end if - return buf; -} //end of the function AAS_LoadAASLump -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_DData(unsigned char *data, int size) -{ - int i; - - for (i = 0; i < size; i++) - { - data[i] ^= (unsigned char) i * 119; - } //end for -} //end of the function AAS_DData -//=========================================================================== -// load an aas file -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_LoadAASFile(char *filename) -{ - fileHandle_t fp; - aas_header_t header; - int offset, length, lastoffset; - - botimport.Print(PRT_MESSAGE, "trying to load %s\n", filename); - //dump current loaded aas file - AAS_DumpAASData(); - //open the file - botimport.FS_FOpenFile( filename, &fp, FS_READ ); - if (!fp) - { - AAS_Error("can't open %s\n", filename); - return BLERR_CANNOTOPENAASFILE; - } //end if - //read the header - botimport.FS_Read(&header, sizeof(aas_header_t), fp ); - lastoffset = sizeof(aas_header_t); - //check header identification - header.ident = LittleLong(header.ident); - if (header.ident != AASID) - { - AAS_Error("%s is not an AAS file\n", filename); - botimport.FS_FCloseFile(fp); - return BLERR_WRONGAASFILEID; - } //end if - //check the version - header.version = LittleLong(header.version); - // - if (header.version != AASVERSION_OLD && header.version != AASVERSION) - { - AAS_Error("aas file %s is version %i, not %i\n", filename, header.version, AASVERSION); - botimport.FS_FCloseFile(fp); - return BLERR_WRONGAASFILEVERSION; - } //end if - // - if (header.version == AASVERSION) - { - AAS_DData((unsigned char *) &header + 8, sizeof(aas_header_t) - 8); - } //end if - // - aasworld.bspchecksum = atoi(LibVarGetString( "sv_mapChecksum")); - if (LittleLong(header.bspchecksum) != aasworld.bspchecksum) - { - AAS_Error("aas file %s is out of date\n", filename); - botimport.FS_FCloseFile(fp); - return BLERR_WRONGAASFILEVERSION; - } //end if - //load the lumps: - //bounding boxes - offset = LittleLong(header.lumps[AASLUMP_BBOXES].fileofs); - length = LittleLong(header.lumps[AASLUMP_BBOXES].filelen); - aasworld.bboxes = (aas_bbox_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_bbox_t)); - aasworld.numbboxes = length / sizeof(aas_bbox_t); - if (aasworld.numbboxes && !aasworld.bboxes) return BLERR_CANNOTREADAASLUMP; - //vertexes - offset = LittleLong(header.lumps[AASLUMP_VERTEXES].fileofs); - length = LittleLong(header.lumps[AASLUMP_VERTEXES].filelen); - aasworld.vertexes = (aas_vertex_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_vertex_t)); - aasworld.numvertexes = length / sizeof(aas_vertex_t); - if (aasworld.numvertexes && !aasworld.vertexes) return BLERR_CANNOTREADAASLUMP; - //planes - offset = LittleLong(header.lumps[AASLUMP_PLANES].fileofs); - length = LittleLong(header.lumps[AASLUMP_PLANES].filelen); - aasworld.planes = (aas_plane_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_plane_t)); - aasworld.numplanes = length / sizeof(aas_plane_t); - if (aasworld.numplanes && !aasworld.planes) return BLERR_CANNOTREADAASLUMP; - //edges - offset = LittleLong(header.lumps[AASLUMP_EDGES].fileofs); - length = LittleLong(header.lumps[AASLUMP_EDGES].filelen); - aasworld.edges = (aas_edge_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_edge_t)); - aasworld.numedges = length / sizeof(aas_edge_t); - if (aasworld.numedges && !aasworld.edges) return BLERR_CANNOTREADAASLUMP; - //edgeindex - offset = LittleLong(header.lumps[AASLUMP_EDGEINDEX].fileofs); - length = LittleLong(header.lumps[AASLUMP_EDGEINDEX].filelen); - aasworld.edgeindex = (aas_edgeindex_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_edgeindex_t)); - aasworld.edgeindexsize = length / sizeof(aas_edgeindex_t); - if (aasworld.edgeindexsize && !aasworld.edgeindex) return BLERR_CANNOTREADAASLUMP; - //faces - offset = LittleLong(header.lumps[AASLUMP_FACES].fileofs); - length = LittleLong(header.lumps[AASLUMP_FACES].filelen); - aasworld.faces = (aas_face_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_face_t)); - aasworld.numfaces = length / sizeof(aas_face_t); - if (aasworld.numfaces && !aasworld.faces) return BLERR_CANNOTREADAASLUMP; - //faceindex - offset = LittleLong(header.lumps[AASLUMP_FACEINDEX].fileofs); - length = LittleLong(header.lumps[AASLUMP_FACEINDEX].filelen); - aasworld.faceindex = (aas_faceindex_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_faceindex_t)); - aasworld.faceindexsize = length / sizeof(aas_faceindex_t); - if (aasworld.faceindexsize && !aasworld.faceindex) return BLERR_CANNOTREADAASLUMP; - //convex areas - offset = LittleLong(header.lumps[AASLUMP_AREAS].fileofs); - length = LittleLong(header.lumps[AASLUMP_AREAS].filelen); - aasworld.areas = (aas_area_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_area_t)); - aasworld.numareas = length / sizeof(aas_area_t); - if (aasworld.numareas && !aasworld.areas) return BLERR_CANNOTREADAASLUMP; - //area settings - offset = LittleLong(header.lumps[AASLUMP_AREASETTINGS].fileofs); - length = LittleLong(header.lumps[AASLUMP_AREASETTINGS].filelen); - aasworld.areasettings = (aas_areasettings_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_areasettings_t)); - aasworld.numareasettings = length / sizeof(aas_areasettings_t); - if (aasworld.numareasettings && !aasworld.areasettings) return BLERR_CANNOTREADAASLUMP; - //reachability list - offset = LittleLong(header.lumps[AASLUMP_REACHABILITY].fileofs); - length = LittleLong(header.lumps[AASLUMP_REACHABILITY].filelen); - aasworld.reachability = (aas_reachability_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_reachability_t)); - aasworld.reachabilitysize = length / sizeof(aas_reachability_t); - if (aasworld.reachabilitysize && !aasworld.reachability) return BLERR_CANNOTREADAASLUMP; - //nodes - offset = LittleLong(header.lumps[AASLUMP_NODES].fileofs); - length = LittleLong(header.lumps[AASLUMP_NODES].filelen); - aasworld.nodes = (aas_node_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_node_t)); - aasworld.numnodes = length / sizeof(aas_node_t); - if (aasworld.numnodes && !aasworld.nodes) return BLERR_CANNOTREADAASLUMP; - //cluster portals - offset = LittleLong(header.lumps[AASLUMP_PORTALS].fileofs); - length = LittleLong(header.lumps[AASLUMP_PORTALS].filelen); - aasworld.portals = (aas_portal_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_portal_t)); - aasworld.numportals = length / sizeof(aas_portal_t); - if (aasworld.numportals && !aasworld.portals) return BLERR_CANNOTREADAASLUMP; - //cluster portal index - offset = LittleLong(header.lumps[AASLUMP_PORTALINDEX].fileofs); - length = LittleLong(header.lumps[AASLUMP_PORTALINDEX].filelen); - aasworld.portalindex = (aas_portalindex_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_portalindex_t)); - aasworld.portalindexsize = length / sizeof(aas_portalindex_t); - if (aasworld.portalindexsize && !aasworld.portalindex) return BLERR_CANNOTREADAASLUMP; - //clusters - offset = LittleLong(header.lumps[AASLUMP_CLUSTERS].fileofs); - length = LittleLong(header.lumps[AASLUMP_CLUSTERS].filelen); - aasworld.clusters = (aas_cluster_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_cluster_t)); - aasworld.numclusters = length / sizeof(aas_cluster_t); - if (aasworld.numclusters && !aasworld.clusters) return BLERR_CANNOTREADAASLUMP; - //swap everything - AAS_SwapAASData(); - //aas file is loaded - aasworld.loaded = qtrue; - //close the file - botimport.FS_FCloseFile(fp); - // -#ifdef AASFILEDEBUG - AAS_FileInfo(); -#endif //AASFILEDEBUG - // - return BLERR_NOERROR; -} //end of the function AAS_LoadAASFile -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -static int AAS_WriteAASLump_offset; - -int AAS_WriteAASLump(fileHandle_t fp, aas_header_t *h, int lumpnum, void *data, int length) -{ - aas_lump_t *lump; - - lump = &h->lumps[lumpnum]; - - lump->fileofs = LittleLong(AAS_WriteAASLump_offset); //LittleLong(ftell(fp)); - lump->filelen = LittleLong(length); - - if (length > 0) - { - botimport.FS_Write(data, length, fp ); - } //end if - - AAS_WriteAASLump_offset += length; - - return qtrue; -} //end of the function AAS_WriteAASLump -//=========================================================================== -// aas data is useless after writing to file because it is byte swapped -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -qboolean AAS_WriteAASFile(char *filename) -{ - aas_header_t header; - fileHandle_t fp; - - botimport.Print(PRT_MESSAGE, "writing %s\n", filename); - //swap the aas data - AAS_SwapAASData(); - //initialize the file header - Com_Memset(&header, 0, sizeof(aas_header_t)); - header.ident = LittleLong(AASID); - header.version = LittleLong(AASVERSION); - header.bspchecksum = LittleLong(aasworld.bspchecksum); - //open a new file - botimport.FS_FOpenFile( filename, &fp, FS_WRITE ); - if (!fp) - { - botimport.Print(PRT_ERROR, "error opening %s\n", filename); - return qfalse; - } //end if - //write the header - botimport.FS_Write(&header, sizeof(aas_header_t), fp); - AAS_WriteAASLump_offset = sizeof(aas_header_t); - //add the data lumps to the file - if (!AAS_WriteAASLump(fp, &header, AASLUMP_BBOXES, aasworld.bboxes, - aasworld.numbboxes * sizeof(aas_bbox_t))) return qfalse; - if (!AAS_WriteAASLump(fp, &header, AASLUMP_VERTEXES, aasworld.vertexes, - aasworld.numvertexes * sizeof(aas_vertex_t))) return qfalse; - if (!AAS_WriteAASLump(fp, &header, AASLUMP_PLANES, aasworld.planes, - aasworld.numplanes * sizeof(aas_plane_t))) return qfalse; - if (!AAS_WriteAASLump(fp, &header, AASLUMP_EDGES, aasworld.edges, - aasworld.numedges * sizeof(aas_edge_t))) return qfalse; - if (!AAS_WriteAASLump(fp, &header, AASLUMP_EDGEINDEX, aasworld.edgeindex, - aasworld.edgeindexsize * sizeof(aas_edgeindex_t))) return qfalse; - if (!AAS_WriteAASLump(fp, &header, AASLUMP_FACES, aasworld.faces, - aasworld.numfaces * sizeof(aas_face_t))) return qfalse; - if (!AAS_WriteAASLump(fp, &header, AASLUMP_FACEINDEX, aasworld.faceindex, - aasworld.faceindexsize * sizeof(aas_faceindex_t))) return qfalse; - if (!AAS_WriteAASLump(fp, &header, AASLUMP_AREAS, aasworld.areas, - aasworld.numareas * sizeof(aas_area_t))) return qfalse; - if (!AAS_WriteAASLump(fp, &header, AASLUMP_AREASETTINGS, aasworld.areasettings, - aasworld.numareasettings * sizeof(aas_areasettings_t))) return qfalse; - if (!AAS_WriteAASLump(fp, &header, AASLUMP_REACHABILITY, aasworld.reachability, - aasworld.reachabilitysize * sizeof(aas_reachability_t))) return qfalse; - if (!AAS_WriteAASLump(fp, &header, AASLUMP_NODES, aasworld.nodes, - aasworld.numnodes * sizeof(aas_node_t))) return qfalse; - if (!AAS_WriteAASLump(fp, &header, AASLUMP_PORTALS, aasworld.portals, - aasworld.numportals * sizeof(aas_portal_t))) return qfalse; - if (!AAS_WriteAASLump(fp, &header, AASLUMP_PORTALINDEX, aasworld.portalindex, - aasworld.portalindexsize * sizeof(aas_portalindex_t))) return qfalse; - if (!AAS_WriteAASLump(fp, &header, AASLUMP_CLUSTERS, aasworld.clusters, - aasworld.numclusters * sizeof(aas_cluster_t))) return qfalse; - //rewrite the header with the added lumps - botimport.FS_Seek(fp, 0, FS_SEEK_SET); - AAS_DData((unsigned char *) &header + 8, sizeof(aas_header_t) - 8); - botimport.FS_Write(&header, sizeof(aas_header_t), fp); - //close the file - botimport.FS_FCloseFile(fp); - return qtrue; -} //end of the function AAS_WriteAASFile diff --git a/src/botlib/be_aas_file.h b/src/botlib/be_aas_file.h deleted file mode 100644 index e5ce3388..00000000 --- a/src/botlib/be_aas_file.h +++ /dev/null @@ -1,43 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_aas_file.h - * - * desc: AAS - * - * $Archive: /source/code/botlib/be_aas_file.h $ - * - *****************************************************************************/ - -#ifdef AASINTERN -//loads the AAS file with the given name -int AAS_LoadAASFile(char *filename); -//writes an AAS file with the given name -qboolean AAS_WriteAASFile(char *filename); -//dumps the loaded AAS data -void AAS_DumpAASData(void); -//print AAS file information -void AAS_FileInfo(void); -#endif //AASINTERN - diff --git a/src/botlib/be_aas_funcs.h b/src/botlib/be_aas_funcs.h deleted file mode 100644 index 9ebb24b4..00000000 --- a/src/botlib/be_aas_funcs.h +++ /dev/null @@ -1,48 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_aas_funcs.h - * - * desc: AAS - * - * $Archive: /source/code/botlib/be_aas_funcs.h $ - * - *****************************************************************************/ - -#ifndef BSPCINCLUDE - -#include "be_aas_main.h" -#include "be_aas_entity.h" -#include "be_aas_sample.h" -#include "be_aas_cluster.h" -#include "be_aas_reach.h" -#include "be_aas_route.h" -#include "be_aas_routealt.h" -#include "be_aas_debug.h" -#include "be_aas_file.h" -#include "be_aas_optimize.h" -#include "be_aas_bsp.h" -#include "be_aas_move.h" - -#endif //BSPCINCLUDE diff --git a/src/botlib/be_aas_main.c b/src/botlib/be_aas_main.c deleted file mode 100644 index 264c784b..00000000 --- a/src/botlib/be_aas_main.c +++ /dev/null @@ -1,430 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_aas_main.c - * - * desc: AAS - * - * $Archive: /MissionPack/code/botlib/be_aas_main.c $ - * - *****************************************************************************/ - -#include "../qcommon/q_shared.h" -#include "l_memory.h" -#include "l_libvar.h" -#include "l_utils.h" -#include "l_script.h" -#include "l_precomp.h" -#include "l_struct.h" -#include "l_log.h" -#include "aasfile.h" -#include "botlib.h" -#include "be_aas.h" -#include "be_aas_funcs.h" -#include "be_interface.h" -#include "be_aas_def.h" - -aas_t aasworld; - -libvar_t *saveroutingcache; - -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void QDECL AAS_Error(char *fmt, ...) -{ - char str[1024]; - va_list arglist; - - va_start(arglist, fmt); - vsprintf(str, fmt, arglist); - va_end(arglist); - botimport.Print(PRT_FATAL, str); -} //end of the function AAS_Error -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -char *AAS_StringFromIndex(char *indexname, char *stringindex[], int numindexes, int index) -{ - if (!aasworld.indexessetup) - { - botimport.Print(PRT_ERROR, "%s: index %d not setup\n", indexname, index); - return ""; - } //end if - if (index < 0 || index >= numindexes) - { - botimport.Print(PRT_ERROR, "%s: index %d out of range\n", indexname, index); - return ""; - } //end if - if (!stringindex[index]) - { - if (index) - { - botimport.Print(PRT_ERROR, "%s: reference to unused index %d\n", indexname, index); - } //end if - return ""; - } //end if - return stringindex[index]; -} //end of the function AAS_StringFromIndex -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_IndexFromString(char *indexname, char *stringindex[], int numindexes, char *string) -{ - int i; - if (!aasworld.indexessetup) - { - botimport.Print(PRT_ERROR, "%s: index not setup \"%s\"\n", indexname, string); - return 0; - } //end if - for (i = 0; i < numindexes; i++) - { - if (!stringindex[i]) continue; - if (!Q_stricmp(stringindex[i], string)) return i; - } //end for - return 0; -} //end of the function AAS_IndexFromString -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -char *AAS_ModelFromIndex(int index) -{ - return AAS_StringFromIndex("ModelFromIndex", &aasworld.configstrings[CS_MODELS], MAX_MODELS, index); -} //end of the function AAS_ModelFromIndex -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_IndexFromModel(char *modelname) -{ - return AAS_IndexFromString("IndexFromModel", &aasworld.configstrings[CS_MODELS], MAX_MODELS, modelname); -} //end of the function AAS_IndexFromModel -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_UpdateStringIndexes(int numconfigstrings, char *configstrings[]) -{ - int i; - //set string pointers and copy the strings - for (i = 0; i < numconfigstrings; i++) - { - if (configstrings[i]) - { - //if (aasworld.configstrings[i]) FreeMemory(aasworld.configstrings[i]); - aasworld.configstrings[i] = (char *) GetMemory(strlen(configstrings[i]) + 1); - strcpy(aasworld.configstrings[i], configstrings[i]); - } //end if - } //end for - aasworld.indexessetup = qtrue; -} //end of the function AAS_UpdateStringIndexes -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_Loaded(void) -{ - return aasworld.loaded; -} //end of the function AAS_Loaded -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_Initialized(void) -{ - return aasworld.initialized; -} //end of the function AAS_Initialized -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_SetInitialized(void) -{ - aasworld.initialized = qtrue; - botimport.Print(PRT_MESSAGE, "AAS initialized.\n"); -#ifdef DEBUG - //create all the routing cache - //AAS_CreateAllRoutingCache(); - // - //AAS_RoutingInfo(); -#endif -} //end of the function AAS_SetInitialized -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_ContinueInit(float time) -{ - //if no AAS file loaded - if (!aasworld.loaded) return; - //if AAS is already initialized - if (aasworld.initialized) return; - //calculate reachability, if not finished return - if (AAS_ContinueInitReachability(time)) return; - //initialize clustering for the new map - AAS_InitClustering(); - //if reachability has been calculated and an AAS file should be written - //or there is a forced data optimization - if (aasworld.savefile || ((int)LibVarGetValue("forcewrite"))) - { - //optimize the AAS data - if ((int)LibVarValue("aasoptimize", "0")) AAS_Optimize(); - //save the AAS file - if (AAS_WriteAASFile(aasworld.filename)) - { - botimport.Print(PRT_MESSAGE, "%s written succesfully\n", aasworld.filename); - } //end if - else - { - botimport.Print(PRT_ERROR, "couldn't write %s\n", aasworld.filename); - } //end else - } //end if - //initialize the routing - AAS_InitRouting(); - //at this point AAS is initialized - AAS_SetInitialized(); -} //end of the function AAS_ContinueInit -//=========================================================================== -// called at the start of every frame -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_StartFrame(float time) -{ - aasworld.time = time; - //unlink all entities that were not updated last frame - AAS_UnlinkInvalidEntities(); - //invalidate the entities - AAS_InvalidateEntities(); - //initialize AAS - AAS_ContinueInit(time); - // - aasworld.frameroutingupdates = 0; - // - if (bot_developer) - { - if (LibVarGetValue("showcacheupdates")) - { - AAS_RoutingInfo(); - LibVarSet("showcacheupdates", "0"); - } //end if - if (LibVarGetValue("showmemoryusage")) - { - PrintUsedMemorySize(); - LibVarSet("showmemoryusage", "0"); - } //end if - if (LibVarGetValue("memorydump")) - { - PrintMemoryLabels(); - LibVarSet("memorydump", "0"); - } //end if - } //end if - // - if (saveroutingcache->value) - { - AAS_WriteRouteCache(); - LibVarSet("saveroutingcache", "0"); - } //end if - // - aasworld.numframes++; - return BLERR_NOERROR; -} //end of the function AAS_StartFrame -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -float AAS_Time(void) -{ - return aasworld.time; -} //end of the function AAS_Time -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_ProjectPointOntoVector( vec3_t point, vec3_t vStart, vec3_t vEnd, vec3_t vProj ) -{ - vec3_t pVec, vec; - - VectorSubtract( point, vStart, pVec ); - VectorSubtract( vEnd, vStart, vec ); - VectorNormalize( vec ); - // project onto the directional vector for this segment - VectorMA( vStart, DotProduct( pVec, vec ), vec, vProj ); -} //end of the function AAS_ProjectPointOntoVector -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_LoadFiles(const char *mapname) -{ - int errnum; - char aasfile[MAX_PATH]; -// char bspfile[MAX_PATH]; - - strcpy(aasworld.mapname, mapname); - //NOTE: first reset the entity links into the AAS areas and BSP leaves - // the AAS link heap and BSP link heap are reset after respectively the - // AAS file and BSP file are loaded - AAS_ResetEntityLinks(); - // load bsp info - AAS_LoadBSPFile(); - - //load the aas file - Com_sprintf(aasfile, MAX_PATH, "maps/%s.aas", mapname); - errnum = AAS_LoadAASFile(aasfile); - if (errnum != BLERR_NOERROR) - return errnum; - - botimport.Print(PRT_MESSAGE, "loaded %s\n", aasfile); - strncpy(aasworld.filename, aasfile, MAX_PATH); - return BLERR_NOERROR; -} //end of the function AAS_LoadFiles -//=========================================================================== -// called everytime a map changes -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_LoadMap(const char *mapname) -{ - int errnum; - - //if no mapname is provided then the string indexes are updated - if (!mapname) - { - return 0; - } //end if - // - aasworld.initialized = qfalse; - //NOTE: free the routing caches before loading a new map because - // to free the caches the old number of areas, number of clusters - // and number of areas in a clusters must be available - AAS_FreeRoutingCaches(); - //load the map - errnum = AAS_LoadFiles(mapname); - if (errnum != BLERR_NOERROR) - { - aasworld.loaded = qfalse; - return errnum; - } //end if - // - AAS_InitSettings(); - //initialize the AAS link heap for the new map - AAS_InitAASLinkHeap(); - //initialize the AAS linked entities for the new map - AAS_InitAASLinkedEntities(); - //initialize reachability for the new map - AAS_InitReachability(); - //initialize the alternative routing - AAS_InitAlternativeRouting(); - //everything went ok - return 0; -} //end of the function AAS_LoadMap -//=========================================================================== -// called when the library is first loaded -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_Setup(void) -{ - aasworld.maxclients = (int) LibVarValue("maxclients", "128"); - aasworld.maxentities = (int) LibVarValue("maxentities", "1024"); - // as soon as it's set to 1 the routing cache will be saved - saveroutingcache = LibVar("saveroutingcache", "0"); - //allocate memory for the entities - if (aasworld.entities) FreeMemory(aasworld.entities); - aasworld.entities = (aas_entity_t *) GetClearedHunkMemory(aasworld.maxentities * sizeof(aas_entity_t)); - //invalidate all the entities - AAS_InvalidateEntities(); - //force some recalculations - //LibVarSet("forceclustering", "1"); //force clustering calculation - //LibVarSet("forcereachability", "1"); //force reachability calculation - aasworld.numframes = 0; - return BLERR_NOERROR; -} //end of the function AAS_Setup -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_Shutdown(void) -{ - AAS_ShutdownAlternativeRouting(); - // - AAS_DumpBSPData(); - //free routing caches - AAS_FreeRoutingCaches(); - //free aas link heap - AAS_FreeAASLinkHeap(); - //free aas linked entities - AAS_FreeAASLinkedEntities(); - //free the aas data - AAS_DumpAASData(); - //free the entities - if (aasworld.entities) FreeMemory(aasworld.entities); - //clear the aasworld structure - Com_Memset(&aasworld, 0, sizeof(aas_t)); - //aas has not been initialized - aasworld.initialized = qfalse; - //NOTE: as soon as a new .bsp file is loaded the .bsp file memory is - // freed an reallocated, so there's no need to free that memory here - //print shutdown - botimport.Print(PRT_MESSAGE, "AAS shutdown.\n"); -} //end of the function AAS_Shutdown diff --git a/src/botlib/be_aas_main.h b/src/botlib/be_aas_main.h deleted file mode 100644 index 9f978186..00000000 --- a/src/botlib/be_aas_main.h +++ /dev/null @@ -1,62 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_aas_main.h - * - * desc: AAS - * - * $Archive: /source/code/botlib/be_aas_main.h $ - * - *****************************************************************************/ - -#ifdef AASINTERN - -extern aas_t aasworld; - -//AAS error message -void QDECL AAS_Error(char *fmt, ...); -//set AAS initialized -void AAS_SetInitialized(void); -//setup AAS with the given number of entities and clients -int AAS_Setup(void); -//shutdown AAS -void AAS_Shutdown(void); -//start a new map -int AAS_LoadMap(const char *mapname); -//start a new time frame -int AAS_StartFrame(float time); -#endif //AASINTERN - -//returns true if AAS is initialized -int AAS_Initialized(void); -//returns true if the AAS file is loaded -int AAS_Loaded(void); -//returns the model name from the given index -char *AAS_ModelFromIndex(int index); -//returns the index from the given model name -int AAS_IndexFromModel(char *modelname); -//returns the current time -float AAS_Time(void); -// -void AAS_ProjectPointOntoVector( vec3_t point, vec3_t vStart, vec3_t vEnd, vec3_t vProj ); diff --git a/src/botlib/be_aas_move.c b/src/botlib/be_aas_move.c deleted file mode 100644 index bbac80d9..00000000 --- a/src/botlib/be_aas_move.c +++ /dev/null @@ -1,1102 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_aas_move.c - * - * desc: AAS - * - * $Archive: /MissionPack/code/botlib/be_aas_move.c $ - * - *****************************************************************************/ - -#include "../qcommon/q_shared.h" -#include "l_memory.h" -#include "l_script.h" -#include "l_precomp.h" -#include "l_struct.h" -#include "l_libvar.h" -#include "aasfile.h" -#include "botlib.h" -#include "be_aas.h" -#include "be_aas_funcs.h" -#include "be_aas_def.h" - -extern botlib_import_t botimport; - -aas_settings_t aassettings; - -//#define AAS_MOVE_DEBUG - -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_DropToFloor(vec3_t origin, vec3_t mins, vec3_t maxs) -{ - vec3_t end; - bsp_trace_t trace; - - VectorCopy(origin, end); - end[2] -= 100; - trace = AAS_Trace(origin, mins, maxs, end, 0, CONTENTS_SOLID); - if (trace.startsolid) return qfalse; - VectorCopy(trace.endpos, origin); - return qtrue; -} //end of the function AAS_DropToFloor -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_InitSettings(void) -{ - aassettings.phys_gravitydirection[0] = 0; - aassettings.phys_gravitydirection[1] = 0; - aassettings.phys_gravitydirection[2] = -1; - aassettings.phys_friction = LibVarValue("phys_friction", "6"); - aassettings.phys_stopspeed = LibVarValue("phys_stopspeed", "100"); - aassettings.phys_gravity = LibVarValue("phys_gravity", "800"); - aassettings.phys_waterfriction = LibVarValue("phys_waterfriction", "1"); - aassettings.phys_watergravity = LibVarValue("phys_watergravity", "400"); - aassettings.phys_maxvelocity = LibVarValue("phys_maxvelocity", "320"); - aassettings.phys_maxwalkvelocity = LibVarValue("phys_maxwalkvelocity", "320"); - aassettings.phys_maxcrouchvelocity = LibVarValue("phys_maxcrouchvelocity", "100"); - aassettings.phys_maxswimvelocity = LibVarValue("phys_maxswimvelocity", "150"); - aassettings.phys_walkaccelerate = LibVarValue("phys_walkaccelerate", "10"); - aassettings.phys_airaccelerate = LibVarValue("phys_airaccelerate", "1"); - aassettings.phys_swimaccelerate = LibVarValue("phys_swimaccelerate", "4"); - aassettings.phys_maxstep = LibVarValue("phys_maxstep", "19"); - aassettings.phys_maxsteepness = LibVarValue("phys_maxsteepness", "0.7"); - aassettings.phys_maxwaterjump = LibVarValue("phys_maxwaterjump", "18"); - aassettings.phys_maxbarrier = LibVarValue("phys_maxbarrier", "33"); - aassettings.phys_jumpvel = LibVarValue("phys_jumpvel", "270"); - aassettings.phys_falldelta5 = LibVarValue("phys_falldelta5", "40"); - aassettings.phys_falldelta10 = LibVarValue("phys_falldelta10", "60"); - aassettings.rs_waterjump = LibVarValue("rs_waterjump", "400"); - aassettings.rs_teleport = LibVarValue("rs_teleport", "50"); - aassettings.rs_barrierjump = LibVarValue("rs_barrierjump", "100"); - aassettings.rs_startcrouch = LibVarValue("rs_startcrouch", "300"); - aassettings.rs_startgrapple = LibVarValue("rs_startgrapple", "500"); - aassettings.rs_startwalkoffledge = LibVarValue("rs_startwalkoffledge", "70"); - aassettings.rs_startjump = LibVarValue("rs_startjump", "300"); - aassettings.rs_rocketjump = LibVarValue("rs_rocketjump", "500"); - aassettings.rs_bfgjump = LibVarValue("rs_bfgjump", "500"); - aassettings.rs_jumppad = LibVarValue("rs_jumppad", "250"); - aassettings.rs_aircontrolledjumppad = LibVarValue("rs_aircontrolledjumppad", "300"); - aassettings.rs_funcbob = LibVarValue("rs_funcbob", "300"); - aassettings.rs_startelevator = LibVarValue("rs_startelevator", "50"); - aassettings.rs_falldamage5 = LibVarValue("rs_falldamage5", "300"); - aassettings.rs_falldamage10 = LibVarValue("rs_falldamage10", "500"); - aassettings.rs_maxfallheight = LibVarValue("rs_maxfallheight", "0"); - aassettings.rs_maxjumpfallheight = LibVarValue("rs_maxjumpfallheight", "450"); -} //end of the function AAS_InitSettings -//=========================================================================== -// returns qtrue if the bot is against a ladder -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_AgainstLadder(vec3_t origin) -{ - int areanum, i, facenum, side; - vec3_t org; - aas_plane_t *plane; - aas_face_t *face; - aas_area_t *area; - - VectorCopy(origin, org); - areanum = AAS_PointAreaNum(org); - if (!areanum) - { - org[0] += 1; - areanum = AAS_PointAreaNum(org); - if (!areanum) - { - org[1] += 1; - areanum = AAS_PointAreaNum(org); - if (!areanum) - { - org[0] -= 2; - areanum = AAS_PointAreaNum(org); - if (!areanum) - { - org[1] -= 2; - areanum = AAS_PointAreaNum(org); - } //end if - } //end if - } //end if - } //end if - //if in solid... wrrr shouldn't happen - if (!areanum) return qfalse; - //if not in a ladder area - if (!(aasworld.areasettings[areanum].areaflags & AREA_LADDER)) return qfalse; - //if a crouch only area - if (!(aasworld.areasettings[areanum].presencetype & PRESENCE_NORMAL)) return qfalse; - // - area = &aasworld.areas[areanum]; - for (i = 0; i < area->numfaces; i++) - { - facenum = aasworld.faceindex[area->firstface + i]; - side = facenum < 0; - face = &aasworld.faces[abs(facenum)]; - //if the face isn't a ladder face - if (!(face->faceflags & FACE_LADDER)) continue; - //get the plane the face is in - plane = &aasworld.planes[face->planenum ^ side]; - //if the origin is pretty close to the plane - if (abs(DotProduct(plane->normal, origin) - plane->dist) < 3) - { - if (AAS_PointInsideFace(abs(facenum), origin, 0.1f)) return qtrue; - } //end if - } //end for - return qfalse; -} //end of the function AAS_AgainstLadder -//=========================================================================== -// returns qtrue if the bot is on the ground -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_OnGround(vec3_t origin, int presencetype, int passent) -{ - aas_trace_t trace; - vec3_t end, up = {0, 0, 1}; - aas_plane_t *plane; - - VectorCopy(origin, end); - end[2] -= 10; - - trace = AAS_TraceClientBBox(origin, end, presencetype, passent); - - //if in solid - if (trace.startsolid) return qfalse; - //if nothing hit at all - if (trace.fraction >= 1.0) return qfalse; - //if too far from the hit plane - if (origin[2] - trace.endpos[2] > 10) return qfalse; - //check if the plane isn't too steep - plane = AAS_PlaneFromNum(trace.planenum); - if (DotProduct(plane->normal, up) < aassettings.phys_maxsteepness) return qfalse; - //the bot is on the ground - return qtrue; -} //end of the function AAS_OnGround -//=========================================================================== -// returns qtrue if a bot at the given position is swimming -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_Swimming(vec3_t origin) -{ - vec3_t testorg; - - VectorCopy(origin, testorg); - testorg[2] -= 2; - if (AAS_PointContents(testorg) & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER)) return qtrue; - return qfalse; -} //end of the function AAS_Swimming -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -static vec3_t VEC_UP = {0, -1, 0}; -static vec3_t MOVEDIR_UP = {0, 0, 1}; -static vec3_t VEC_DOWN = {0, -2, 0}; -static vec3_t MOVEDIR_DOWN = {0, 0, -1}; - -void AAS_SetMovedir(vec3_t angles, vec3_t movedir) -{ - if (VectorCompare(angles, VEC_UP)) - { - VectorCopy(MOVEDIR_UP, movedir); - } //end if - else if (VectorCompare(angles, VEC_DOWN)) - { - VectorCopy(MOVEDIR_DOWN, movedir); - } //end else if - else - { - AngleVectors(angles, movedir, NULL, NULL); - } //end else -} //end of the function AAS_SetMovedir -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_JumpReachRunStart(aas_reachability_t *reach, vec3_t runstart) -{ - vec3_t hordir, start, cmdmove; - aas_clientmove_t move; - - // - hordir[0] = reach->start[0] - reach->end[0]; - hordir[1] = reach->start[1] - reach->end[1]; - hordir[2] = 0; - VectorNormalize(hordir); - //start point - VectorCopy(reach->start, start); - start[2] += 1; - //get command movement - VectorScale(hordir, 400, cmdmove); - // - AAS_PredictClientMovement(&move, -1, start, PRESENCE_NORMAL, qtrue, - vec3_origin, cmdmove, 1, 2, 0.1f, - SE_ENTERWATER|SE_ENTERSLIME|SE_ENTERLAVA| - SE_HITGROUNDDAMAGE|SE_GAP, 0, qfalse); - VectorCopy(move.endpos, runstart); - //don't enter slime or lava and don't fall from too high - if (move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA|SE_HITGROUNDDAMAGE)) - { - VectorCopy(start, runstart); - } //end if -} //end of the function AAS_JumpReachRunStart -//=========================================================================== -// returns the Z velocity when rocket jumping at the origin -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -float AAS_WeaponJumpZVelocity(vec3_t origin, float radiusdamage) -{ - vec3_t kvel, v, start, end, forward, right, viewangles, dir; - float mass, knockback, points; - vec3_t rocketoffset = {8, 8, -8}; - vec3_t botmins = {-16, -16, -24}; - vec3_t botmaxs = {16, 16, 32}; - bsp_trace_t bsptrace; - - //look down (90 degrees) - viewangles[PITCH] = 90; - viewangles[YAW] = 0; - viewangles[ROLL] = 0; - //get the start point shooting from - VectorCopy(origin, start); - start[2] += 8; //view offset Z - AngleVectors(viewangles, forward, right, NULL); - start[0] += forward[0] * rocketoffset[0] + right[0] * rocketoffset[1]; - start[1] += forward[1] * rocketoffset[0] + right[1] * rocketoffset[1]; - start[2] += forward[2] * rocketoffset[0] + right[2] * rocketoffset[1] + rocketoffset[2]; - //end point of the trace - VectorMA(start, 500, forward, end); - //trace a line to get the impact point - bsptrace = AAS_Trace(start, NULL, NULL, end, 1, CONTENTS_SOLID); - //calculate the damage the bot will get from the rocket impact - VectorAdd(botmins, botmaxs, v); - VectorMA(origin, 0.5, v, v); - VectorSubtract(bsptrace.endpos, v, v); - // - points = radiusdamage - 0.5 * VectorLength(v); - if (points < 0) points = 0; - //the owner of the rocket gets half the damage - points *= 0.5; - //mass of the bot (p_client.c: PutClientInServer) - mass = 200; - //knockback is the same as the damage points - knockback = points; - //direction of the damage (from trace.endpos to bot origin) - VectorSubtract(origin, bsptrace.endpos, dir); - VectorNormalize(dir); - //damage velocity - VectorScale(dir, 1600.0 * (float)knockback / mass, kvel); //the rocket jump hack... - //rocket impact velocity + jump velocity - return kvel[2] + aassettings.phys_jumpvel; -} //end of the function AAS_WeaponJumpZVelocity -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -float AAS_RocketJumpZVelocity(vec3_t origin) -{ - //rocket radius damage is 120 (p_weapon.c: Weapon_RocketLauncher_Fire) - return AAS_WeaponJumpZVelocity(origin, 120); -} //end of the function AAS_RocketJumpZVelocity -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -float AAS_BFGJumpZVelocity(vec3_t origin) -{ - //bfg radius damage is 1000 (p_weapon.c: weapon_bfg_fire) - return AAS_WeaponJumpZVelocity(origin, 120); -} //end of the function AAS_BFGJumpZVelocity -//=========================================================================== -// applies ground friction to the given velocity -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_Accelerate(vec3_t velocity, float frametime, vec3_t wishdir, float wishspeed, float accel) -{ - // q2 style - int i; - float addspeed, accelspeed, currentspeed; - - currentspeed = DotProduct(velocity, wishdir); - addspeed = wishspeed - currentspeed; - if (addspeed <= 0) { - return; - } - accelspeed = accel*frametime*wishspeed; - if (accelspeed > addspeed) { - accelspeed = addspeed; - } - - for (i=0 ; i<3 ; i++) { - velocity[i] += accelspeed*wishdir[i]; - } -} //end of the function AAS_Accelerate -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_AirControl(vec3_t start, vec3_t end, vec3_t velocity, vec3_t cmdmove) -{ - vec3_t dir; - - VectorSubtract(end, start, dir); -} //end of the function AAS_AirControl -//=========================================================================== -// applies ground friction to the given velocity -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_ApplyFriction(vec3_t vel, float friction, float stopspeed, - float frametime) -{ - float speed, control, newspeed; - - //horizontal speed - speed = sqrt(vel[0] * vel[0] + vel[1] * vel[1]); - if (speed) - { - control = speed < stopspeed ? stopspeed : speed; - newspeed = speed - frametime * control * friction; - if (newspeed < 0) newspeed = 0; - newspeed /= speed; - vel[0] *= newspeed; - vel[1] *= newspeed; - } //end if -} //end of the function AAS_ApplyFriction -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_ClipToBBox(aas_trace_t *trace, vec3_t start, vec3_t end, int presencetype, vec3_t mins, vec3_t maxs) -{ - int i, j, side; - float front, back, frac, planedist; - vec3_t bboxmins, bboxmaxs, absmins, absmaxs, dir, mid; - - AAS_PresenceTypeBoundingBox(presencetype, bboxmins, bboxmaxs); - VectorSubtract(mins, bboxmaxs, absmins); - VectorSubtract(maxs, bboxmins, absmaxs); - // - VectorCopy(end, trace->endpos); - trace->fraction = 1; - for (i = 0; i < 3; i++) - { - if (start[i] < absmins[i] && end[i] < absmins[i]) return qfalse; - if (start[i] > absmaxs[i] && end[i] > absmaxs[i]) return qfalse; - } //end for - //check bounding box collision - VectorSubtract(end, start, dir); - frac = 1; - for (i = 0; i < 3; i++) - { - //get plane to test collision with for the current axis direction - if (dir[i] > 0) planedist = absmins[i]; - else planedist = absmaxs[i]; - //calculate collision fraction - front = start[i] - planedist; - back = end[i] - planedist; - frac = front / (front-back); - //check if between bounding planes of next axis - side = i + 1; - if (side > 2) side = 0; - mid[side] = start[side] + dir[side] * frac; - if (mid[side] > absmins[side] && mid[side] < absmaxs[side]) - { - //check if between bounding planes of next axis - side++; - if (side > 2) side = 0; - mid[side] = start[side] + dir[side] * frac; - if (mid[side] > absmins[side] && mid[side] < absmaxs[side]) - { - mid[i] = planedist; - break; - } //end if - } //end if - } //end for - //if there was a collision - if (i != 3) - { - trace->startsolid = qfalse; - trace->fraction = frac; - trace->ent = 0; - trace->planenum = 0; - trace->area = 0; - trace->lastarea = 0; - //trace endpos - for (j = 0; j < 3; j++) trace->endpos[j] = start[j] + dir[j] * frac; - return qtrue; - } //end if - return qfalse; -} //end of the function AAS_ClipToBBox -//=========================================================================== -// predicts the movement -// assumes regular bounding box sizes -// NOTE: out of water jumping is not included -// NOTE: grappling hook is not included -// -// Parameter: origin : origin to start with -// presencetype : presence type to start with -// velocity : velocity to start with -// cmdmove : client command movement -// cmdframes : number of frame cmdmove is valid -// maxframes : maximum number of predicted frames -// frametime : duration of one predicted frame -// stopevent : events that stop the prediction -// stopareanum : stop as soon as entered this area -// Returns: aas_clientmove_t -// Changes Globals: - -//=========================================================================== -int AAS_ClientMovementPrediction(struct aas_clientmove_s *move, - int entnum, vec3_t origin, - int presencetype, int onground, - vec3_t velocity, vec3_t cmdmove, - int cmdframes, - int maxframes, float frametime, - int stopevent, int stopareanum, - vec3_t mins, vec3_t maxs, int visualize) -{ - float phys_friction, phys_stopspeed, phys_gravity, phys_waterfriction; - float phys_watergravity; - float phys_walkaccelerate, phys_airaccelerate, phys_swimaccelerate; - float phys_maxwalkvelocity, phys_maxcrouchvelocity, phys_maxswimvelocity; - float phys_maxstep, phys_maxsteepness, phys_jumpvel, friction; - float gravity, delta, maxvel, wishspeed, accelerate; - //float velchange, newvel; - int n, i, j, pc, step, swimming, ax, crouch, event, jump_frame, areanum; - int areas[20], numareas; - vec3_t points[20]; - vec3_t org, end, feet, start, stepend, lastorg, wishdir; - vec3_t frame_test_vel, old_frame_test_vel, left_test_vel; - vec3_t up = {0, 0, 1}; - aas_plane_t *plane, *plane2; - aas_trace_t trace, steptrace; - - if (frametime <= 0) frametime = 0.1f; - // - phys_friction = aassettings.phys_friction; - phys_stopspeed = aassettings.phys_stopspeed; - phys_gravity = aassettings.phys_gravity; - phys_waterfriction = aassettings.phys_waterfriction; - phys_watergravity = aassettings.phys_watergravity; - phys_maxwalkvelocity = aassettings.phys_maxwalkvelocity;// * frametime; - phys_maxcrouchvelocity = aassettings.phys_maxcrouchvelocity;// * frametime; - phys_maxswimvelocity = aassettings.phys_maxswimvelocity;// * frametime; - phys_walkaccelerate = aassettings.phys_walkaccelerate; - phys_airaccelerate = aassettings.phys_airaccelerate; - phys_swimaccelerate = aassettings.phys_swimaccelerate; - phys_maxstep = aassettings.phys_maxstep; - phys_maxsteepness = aassettings.phys_maxsteepness; - phys_jumpvel = aassettings.phys_jumpvel * frametime; - // - Com_Memset(move, 0, sizeof(aas_clientmove_t)); - Com_Memset(&trace, 0, sizeof(aas_trace_t)); - //start at the current origin - VectorCopy(origin, org); - org[2] += 0.25; - //velocity to test for the first frame - VectorScale(velocity, frametime, frame_test_vel); - // - jump_frame = -1; - //predict a maximum of 'maxframes' ahead - for (n = 0; n < maxframes; n++) - { - swimming = AAS_Swimming(org); - //get gravity depending on swimming or not - gravity = swimming ? phys_watergravity : phys_gravity; - //apply gravity at the START of the frame - frame_test_vel[2] = frame_test_vel[2] - (gravity * 0.1 * frametime); - //if on the ground or swimming - if (onground || swimming) - { - friction = swimming ? phys_friction : phys_waterfriction; - //apply friction - VectorScale(frame_test_vel, 1/frametime, frame_test_vel); - AAS_ApplyFriction(frame_test_vel, friction, phys_stopspeed, frametime); - VectorScale(frame_test_vel, frametime, frame_test_vel); - } //end if - crouch = qfalse; - //apply command movement - if (n < cmdframes) - { - ax = 0; - maxvel = phys_maxwalkvelocity; - accelerate = phys_airaccelerate; - VectorCopy(cmdmove, wishdir); - if (onground) - { - if (cmdmove[2] < -300) - { - crouch = qtrue; - maxvel = phys_maxcrouchvelocity; - } //end if - //if not swimming and upmove is positive then jump - if (!swimming && cmdmove[2] > 1) - { - //jump velocity minus the gravity for one frame + 5 for safety - frame_test_vel[2] = phys_jumpvel - (gravity * 0.1 * frametime) + 5; - jump_frame = n; - //jumping so air accelerate - accelerate = phys_airaccelerate; - } //end if - else - { - accelerate = phys_walkaccelerate; - } //end else - ax = 2; - } //end if - if (swimming) - { - maxvel = phys_maxswimvelocity; - accelerate = phys_swimaccelerate; - ax = 3; - } //end if - else - { - wishdir[2] = 0; - } //end else - // - wishspeed = VectorNormalize(wishdir); - if (wishspeed > maxvel) wishspeed = maxvel; - VectorScale(frame_test_vel, 1/frametime, frame_test_vel); - AAS_Accelerate(frame_test_vel, frametime, wishdir, wishspeed, accelerate); - VectorScale(frame_test_vel, frametime, frame_test_vel); - /* - for (i = 0; i < ax; i++) - { - velchange = (cmdmove[i] * frametime) - frame_test_vel[i]; - if (velchange > phys_maxacceleration) velchange = phys_maxacceleration; - else if (velchange < -phys_maxacceleration) velchange = -phys_maxacceleration; - newvel = frame_test_vel[i] + velchange; - // - if (frame_test_vel[i] <= maxvel && newvel > maxvel) frame_test_vel[i] = maxvel; - else if (frame_test_vel[i] >= -maxvel && newvel < -maxvel) frame_test_vel[i] = -maxvel; - else frame_test_vel[i] = newvel; - } //end for - */ - } //end if - if (crouch) - { - presencetype = PRESENCE_CROUCH; - } //end if - else if (presencetype == PRESENCE_CROUCH) - { - if (AAS_PointPresenceType(org) & PRESENCE_NORMAL) - { - presencetype = PRESENCE_NORMAL; - } //end if - } //end else - //save the current origin - VectorCopy(org, lastorg); - //move linear during one frame - VectorCopy(frame_test_vel, left_test_vel); - j = 0; - do - { - VectorAdd(org, left_test_vel, end); - //trace a bounding box - trace = AAS_TraceClientBBox(org, end, presencetype, entnum); - // -//#ifdef AAS_MOVE_DEBUG - if (visualize) - { - if (trace.startsolid) botimport.Print(PRT_MESSAGE, "PredictMovement: start solid\n"); - AAS_DebugLine(org, trace.endpos, LINECOLOR_RED); - } //end if -//#endif //AAS_MOVE_DEBUG - // - if (stopevent & (SE_ENTERAREA|SE_TOUCHJUMPPAD|SE_TOUCHTELEPORTER|SE_TOUCHCLUSTERPORTAL)) - { - numareas = AAS_TraceAreas(org, trace.endpos, areas, points, 20); - for (i = 0; i < numareas; i++) - { - if (stopevent & SE_ENTERAREA) - { - if (areas[i] == stopareanum) - { - VectorCopy(points[i], move->endpos); - VectorScale(frame_test_vel, 1/frametime, move->velocity); - move->endarea = areas[i]; - move->trace = trace; - move->stopevent = SE_ENTERAREA; - move->presencetype = presencetype; - move->endcontents = 0; - move->time = n * frametime; - move->frames = n; - return qtrue; - } //end if - } //end if - //NOTE: if not the first frame - if ((stopevent & SE_TOUCHJUMPPAD) && n) - { - if (aasworld.areasettings[areas[i]].contents & AREACONTENTS_JUMPPAD) - { - VectorCopy(points[i], move->endpos); - VectorScale(frame_test_vel, 1/frametime, move->velocity); - move->endarea = areas[i]; - move->trace = trace; - move->stopevent = SE_TOUCHJUMPPAD; - move->presencetype = presencetype; - move->endcontents = 0; - move->time = n * frametime; - move->frames = n; - return qtrue; - } //end if - } //end if - if (stopevent & SE_TOUCHTELEPORTER) - { - if (aasworld.areasettings[areas[i]].contents & AREACONTENTS_TELEPORTER) - { - VectorCopy(points[i], move->endpos); - move->endarea = areas[i]; - VectorScale(frame_test_vel, 1/frametime, move->velocity); - move->trace = trace; - move->stopevent = SE_TOUCHTELEPORTER; - move->presencetype = presencetype; - move->endcontents = 0; - move->time = n * frametime; - move->frames = n; - return qtrue; - } //end if - } //end if - if (stopevent & SE_TOUCHCLUSTERPORTAL) - { - if (aasworld.areasettings[areas[i]].contents & AREACONTENTS_CLUSTERPORTAL) - { - VectorCopy(points[i], move->endpos); - move->endarea = areas[i]; - VectorScale(frame_test_vel, 1/frametime, move->velocity); - move->trace = trace; - move->stopevent = SE_TOUCHCLUSTERPORTAL; - move->presencetype = presencetype; - move->endcontents = 0; - move->time = n * frametime; - move->frames = n; - return qtrue; - } //end if - } //end if - } //end for - } //end if - // - if (stopevent & SE_HITBOUNDINGBOX) - { - if (AAS_ClipToBBox(&trace, org, trace.endpos, presencetype, mins, maxs)) - { - VectorCopy(trace.endpos, move->endpos); - move->endarea = AAS_PointAreaNum(move->endpos); - VectorScale(frame_test_vel, 1/frametime, move->velocity); - move->trace = trace; - move->stopevent = SE_HITBOUNDINGBOX; - move->presencetype = presencetype; - move->endcontents = 0; - move->time = n * frametime; - move->frames = n; - return qtrue; - } //end if - } //end if - //move the entity to the trace end point - VectorCopy(trace.endpos, org); - //if there was a collision - if (trace.fraction < 1.0) - { - //get the plane the bounding box collided with - plane = AAS_PlaneFromNum(trace.planenum); - // - if (stopevent & SE_HITGROUNDAREA) - { - if (DotProduct(plane->normal, up) > phys_maxsteepness) - { - VectorCopy(org, start); - start[2] += 0.5; - if (AAS_PointAreaNum(start) == stopareanum) - { - VectorCopy(start, move->endpos); - move->endarea = stopareanum; - VectorScale(frame_test_vel, 1/frametime, move->velocity); - move->trace = trace; - move->stopevent = SE_HITGROUNDAREA; - move->presencetype = presencetype; - move->endcontents = 0; - move->time = n * frametime; - move->frames = n; - return qtrue; - } //end if - } //end if - } //end if - //assume there's no step - step = qfalse; - //if it is a vertical plane and the bot didn't jump recently - if (plane->normal[2] == 0 && (jump_frame < 0 || n - jump_frame > 2)) - { - //check for a step - VectorMA(org, -0.25, plane->normal, start); - VectorCopy(start, stepend); - start[2] += phys_maxstep; - steptrace = AAS_TraceClientBBox(start, stepend, presencetype, entnum); - // - if (!steptrace.startsolid) - { - plane2 = AAS_PlaneFromNum(steptrace.planenum); - if (DotProduct(plane2->normal, up) > phys_maxsteepness) - { - VectorSubtract(end, steptrace.endpos, left_test_vel); - left_test_vel[2] = 0; - frame_test_vel[2] = 0; -//#ifdef AAS_MOVE_DEBUG - if (visualize) - { - if (steptrace.endpos[2] - org[2] > 0.125) - { - VectorCopy(org, start); - start[2] = steptrace.endpos[2]; - AAS_DebugLine(org, start, LINECOLOR_BLUE); - } //end if - } //end if -//#endif //AAS_MOVE_DEBUG - org[2] = steptrace.endpos[2]; - step = qtrue; - } //end if - } //end if - } //end if - // - if (!step) - { - //velocity left to test for this frame is the projection - //of the current test velocity into the hit plane - VectorMA(left_test_vel, -DotProduct(left_test_vel, plane->normal), - plane->normal, left_test_vel); - //store the old velocity for landing check - VectorCopy(frame_test_vel, old_frame_test_vel); - //test velocity for the next frame is the projection - //of the velocity of the current frame into the hit plane - VectorMA(frame_test_vel, -DotProduct(frame_test_vel, plane->normal), - plane->normal, frame_test_vel); - //check for a landing on an almost horizontal floor - if (DotProduct(plane->normal, up) > phys_maxsteepness) - { - onground = qtrue; - } //end if - if (stopevent & SE_HITGROUNDDAMAGE) - { - delta = 0; - if (old_frame_test_vel[2] < 0 && - frame_test_vel[2] > old_frame_test_vel[2] && - !onground) - { - delta = old_frame_test_vel[2]; - } //end if - else if (onground) - { - delta = frame_test_vel[2] - old_frame_test_vel[2]; - } //end else - if (delta) - { - delta = delta * 10; - delta = delta * delta * 0.0001; - if (swimming) delta = 0; - // never take falling damage if completely underwater - /* - if (ent->waterlevel == 3) return; - if (ent->waterlevel == 2) delta *= 0.25; - if (ent->waterlevel == 1) delta *= 0.5; - */ - if (delta > 40) - { - VectorCopy(org, move->endpos); - move->endarea = AAS_PointAreaNum(org); - VectorCopy(frame_test_vel, move->velocity); - move->trace = trace; - move->stopevent = SE_HITGROUNDDAMAGE; - move->presencetype = presencetype; - move->endcontents = 0; - move->time = n * frametime; - move->frames = n; - return qtrue; - } //end if - } //end if - } //end if - } //end if - } //end if - //extra check to prevent endless loop - if (++j > 20) return qfalse; - //while there is a plane hit - } while(trace.fraction < 1.0); - //if going down - if (frame_test_vel[2] <= 10) - { - //check for a liquid at the feet of the bot - VectorCopy(org, feet); - feet[2] -= 22; - pc = AAS_PointContents(feet); - //get event from pc - event = SE_NONE; - if (pc & CONTENTS_LAVA) event |= SE_ENTERLAVA; - if (pc & CONTENTS_SLIME) event |= SE_ENTERSLIME; - if (pc & CONTENTS_WATER) event |= SE_ENTERWATER; - // - areanum = AAS_PointAreaNum(org); - if (aasworld.areasettings[areanum].contents & AREACONTENTS_LAVA) - event |= SE_ENTERLAVA; - if (aasworld.areasettings[areanum].contents & AREACONTENTS_SLIME) - event |= SE_ENTERSLIME; - if (aasworld.areasettings[areanum].contents & AREACONTENTS_WATER) - event |= SE_ENTERWATER; - //if in lava or slime - if (event & stopevent) - { - VectorCopy(org, move->endpos); - move->endarea = areanum; - VectorScale(frame_test_vel, 1/frametime, move->velocity); - move->stopevent = event & stopevent; - move->presencetype = presencetype; - move->endcontents = pc; - move->time = n * frametime; - move->frames = n; - return qtrue; - } //end if - } //end if - // - onground = AAS_OnGround(org, presencetype, entnum); - //if onground and on the ground for at least one whole frame - if (onground) - { - if (stopevent & SE_HITGROUND) - { - VectorCopy(org, move->endpos); - move->endarea = AAS_PointAreaNum(org); - VectorScale(frame_test_vel, 1/frametime, move->velocity); - move->trace = trace; - move->stopevent = SE_HITGROUND; - move->presencetype = presencetype; - move->endcontents = 0; - move->time = n * frametime; - move->frames = n; - return qtrue; - } //end if - } //end if - else if (stopevent & SE_LEAVEGROUND) - { - VectorCopy(org, move->endpos); - move->endarea = AAS_PointAreaNum(org); - VectorScale(frame_test_vel, 1/frametime, move->velocity); - move->trace = trace; - move->stopevent = SE_LEAVEGROUND; - move->presencetype = presencetype; - move->endcontents = 0; - move->time = n * frametime; - move->frames = n; - return qtrue; - } //end else if - else if (stopevent & SE_GAP) - { - aas_trace_t gaptrace; - - VectorCopy(org, start); - VectorCopy(start, end); - end[2] -= 48 + aassettings.phys_maxbarrier; - gaptrace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, -1); - //if solid is found the bot cannot walk any further and will not fall into a gap - if (!gaptrace.startsolid) - { - //if it is a gap (lower than one step height) - if (gaptrace.endpos[2] < org[2] - aassettings.phys_maxstep - 1) - { - if (!(AAS_PointContents(end) & CONTENTS_WATER)) - { - VectorCopy(lastorg, move->endpos); - move->endarea = AAS_PointAreaNum(lastorg); - VectorScale(frame_test_vel, 1/frametime, move->velocity); - move->trace = trace; - move->stopevent = SE_GAP; - move->presencetype = presencetype; - move->endcontents = 0; - move->time = n * frametime; - move->frames = n; - return qtrue; - } //end if - } //end if - } //end if - } //end else if - } //end for - // - VectorCopy(org, move->endpos); - move->endarea = AAS_PointAreaNum(org); - VectorScale(frame_test_vel, 1/frametime, move->velocity); - move->stopevent = SE_NONE; - move->presencetype = presencetype; - move->endcontents = 0; - move->time = n * frametime; - move->frames = n; - // - return qtrue; -} //end of the function AAS_ClientMovementPrediction -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_PredictClientMovement(struct aas_clientmove_s *move, - int entnum, vec3_t origin, - int presencetype, int onground, - vec3_t velocity, vec3_t cmdmove, - int cmdframes, - int maxframes, float frametime, - int stopevent, int stopareanum, int visualize) -{ - vec3_t mins, maxs; - return AAS_ClientMovementPrediction(move, entnum, origin, presencetype, onground, - velocity, cmdmove, cmdframes, maxframes, - frametime, stopevent, stopareanum, - mins, maxs, visualize); -} //end of the function AAS_PredictClientMovement -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_ClientMovementHitBBox(struct aas_clientmove_s *move, - int entnum, vec3_t origin, - int presencetype, int onground, - vec3_t velocity, vec3_t cmdmove, - int cmdframes, - int maxframes, float frametime, - vec3_t mins, vec3_t maxs, int visualize) -{ - return AAS_ClientMovementPrediction(move, entnum, origin, presencetype, onground, - velocity, cmdmove, cmdframes, maxframes, - frametime, SE_HITBOUNDINGBOX, 0, - mins, maxs, visualize); -} //end of the function AAS_ClientMovementHitBBox -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_TestMovementPrediction(int entnum, vec3_t origin, vec3_t dir) -{ - vec3_t velocity, cmdmove; - aas_clientmove_t move; - - VectorClear(velocity); - if (!AAS_Swimming(origin)) dir[2] = 0; - VectorNormalize(dir); - VectorScale(dir, 400, cmdmove); - cmdmove[2] = 224; - AAS_ClearShownDebugLines(); - AAS_PredictClientMovement(&move, entnum, origin, PRESENCE_NORMAL, qtrue, - velocity, cmdmove, 13, 13, 0.1f, SE_HITGROUND, 0, qtrue);//SE_LEAVEGROUND); - if (move.stopevent & SE_LEAVEGROUND) - { - botimport.Print(PRT_MESSAGE, "leave ground\n"); - } //end if -} //end of the function TestMovementPrediction -//=========================================================================== -// calculates the horizontal velocity needed to perform a jump from start -// to end -// -// Parameter: zvel : z velocity for jump -// start : start position of jump -// end : end position of jump -// *speed : returned speed for jump -// Returns: qfalse if too high or too far from start to end -// Changes Globals: - -//=========================================================================== -int AAS_HorizontalVelocityForJump(float zvel, vec3_t start, vec3_t end, float *velocity) -{ - float phys_gravity, phys_maxvelocity; - float maxjump, height2fall, t, top; - vec3_t dir; - - phys_gravity = aassettings.phys_gravity; - phys_maxvelocity = aassettings.phys_maxvelocity; - - //maximum height a player can jump with the given initial z velocity - maxjump = 0.5 * phys_gravity * (zvel / phys_gravity) * (zvel / phys_gravity); - //top of the parabolic jump - top = start[2] + maxjump; - //height the bot will fall from the top - height2fall = top - end[2]; - //if the goal is to high to jump to - if (height2fall < 0) - { - *velocity = phys_maxvelocity; - return 0; - } //end if - //time a player takes to fall the height - t = sqrt(height2fall / (0.5 * phys_gravity)); - //direction from start to end - VectorSubtract(end, start, dir); - // - if ( (t + zvel / phys_gravity) == 0.0f ) { - *velocity = phys_maxvelocity; - return 0; - } - //calculate horizontal speed - *velocity = sqrt(dir[0]*dir[0] + dir[1]*dir[1]) / (t + zvel / phys_gravity); - //the horizontal speed must be lower than the max speed - if (*velocity > phys_maxvelocity) - { - *velocity = phys_maxvelocity; - return 0; - } //end if - return 1; -} //end of the function AAS_HorizontalVelocityForJump diff --git a/src/botlib/be_aas_move.h b/src/botlib/be_aas_move.h deleted file mode 100644 index 2d09af89..00000000 --- a/src/botlib/be_aas_move.h +++ /dev/null @@ -1,72 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_aas_move.h - * - * desc: AAS - * - * $Archive: /source/code/botlib/be_aas_move.h $ - * - *****************************************************************************/ - -#ifdef AASINTERN -extern aas_settings_t aassettings; -#endif //AASINTERN - -//movement prediction -int AAS_PredictClientMovement(struct aas_clientmove_s *move, - int entnum, vec3_t origin, - int presencetype, int onground, - vec3_t velocity, vec3_t cmdmove, - int cmdframes, - int maxframes, float frametime, - int stopevent, int stopareanum, int visualize); -//predict movement until bounding box is hit -int AAS_ClientMovementHitBBox(struct aas_clientmove_s *move, - int entnum, vec3_t origin, - int presencetype, int onground, - vec3_t velocity, vec3_t cmdmove, - int cmdframes, - int maxframes, float frametime, - vec3_t mins, vec3_t maxs, int visualize); -//returns true if on the ground at the given origin -int AAS_OnGround(vec3_t origin, int presencetype, int passent); -//returns true if swimming at the given origin -int AAS_Swimming(vec3_t origin); -//returns the jump reachability run start point -void AAS_JumpReachRunStart(struct aas_reachability_s *reach, vec3_t runstart); -//returns true if against a ladder at the given origin -int AAS_AgainstLadder(vec3_t origin); -//rocket jump Z velocity when rocket-jumping at origin -float AAS_RocketJumpZVelocity(vec3_t origin); -//bfg jump Z velocity when bfg-jumping at origin -float AAS_BFGJumpZVelocity(vec3_t origin); -//calculates the horizontal velocity needed for a jump and returns true this velocity could be calculated -int AAS_HorizontalVelocityForJump(float zvel, vec3_t start, vec3_t end, float *velocity); -// -void AAS_SetMovedir(vec3_t angles, vec3_t movedir); -// -int AAS_DropToFloor(vec3_t origin, vec3_t mins, vec3_t maxs); -// -void AAS_InitSettings(void); diff --git a/src/botlib/be_aas_optimize.c b/src/botlib/be_aas_optimize.c deleted file mode 100644 index ea91082b..00000000 --- a/src/botlib/be_aas_optimize.c +++ /dev/null @@ -1,313 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_aas_optimize.c - * - * desc: decreases the .aas file size after the reachabilities have - * been calculated, just dumps all the faces, edges and vertexes - * - * $Archive: /MissionPack/code/botlib/be_aas_optimize.c $ - * - *****************************************************************************/ - -#include "../qcommon/q_shared.h" -#include "l_libvar.h" -#include "l_memory.h" -#include "l_script.h" -#include "l_precomp.h" -#include "l_struct.h" -#include "aasfile.h" -#include "botlib.h" -#include "be_aas.h" -#include "be_aas_funcs.h" -#include "be_interface.h" -#include "be_aas_def.h" - -typedef struct optimized_s -{ - //vertexes - int numvertexes; - aas_vertex_t *vertexes; - //edges - int numedges; - aas_edge_t *edges; - //edge index - int edgeindexsize; - aas_edgeindex_t *edgeindex; - //faces - int numfaces; - aas_face_t *faces; - //face index - int faceindexsize; - aas_faceindex_t *faceindex; - //convex areas - int numareas; - aas_area_t *areas; - // - int *vertexoptimizeindex; - int *edgeoptimizeindex; - int *faceoptimizeindex; -} optimized_t; - -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_KeepEdge(aas_edge_t *edge) -{ - return 1; -} //end of the function AAS_KeepFace -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_OptimizeEdge(optimized_t *optimized, int edgenum) -{ - int i, optedgenum; - aas_edge_t *edge, *optedge; - - edge = &aasworld.edges[abs(edgenum)]; - if (!AAS_KeepEdge(edge)) return 0; - - optedgenum = optimized->edgeoptimizeindex[abs(edgenum)]; - if (optedgenum) - { - //keep the edge reversed sign - if (edgenum > 0) return optedgenum; - else return -optedgenum; - } //end if - - optedge = &optimized->edges[optimized->numedges]; - - for (i = 0; i < 2; i++) - { - if (optimized->vertexoptimizeindex[edge->v[i]]) - { - optedge->v[i] = optimized->vertexoptimizeindex[edge->v[i]]; - } //end if - else - { - VectorCopy(aasworld.vertexes[edge->v[i]], optimized->vertexes[optimized->numvertexes]); - optedge->v[i] = optimized->numvertexes; - optimized->vertexoptimizeindex[edge->v[i]] = optimized->numvertexes; - optimized->numvertexes++; - } //end else - } //end for - optimized->edgeoptimizeindex[abs(edgenum)] = optimized->numedges; - optedgenum = optimized->numedges; - optimized->numedges++; - //keep the edge reversed sign - if (edgenum > 0) return optedgenum; - else return -optedgenum; -} //end of the function AAS_OptimizeEdge -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_KeepFace(aas_face_t *face) -{ - if (!(face->faceflags & FACE_LADDER)) return 0; - else return 1; -} //end of the function AAS_KeepFace -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_OptimizeFace(optimized_t *optimized, int facenum) -{ - int i, edgenum, optedgenum, optfacenum; - aas_face_t *face, *optface; - - face = &aasworld.faces[abs(facenum)]; - if (!AAS_KeepFace(face)) return 0; - - optfacenum = optimized->faceoptimizeindex[abs(facenum)]; - if (optfacenum) - { - //keep the face side sign - if (facenum > 0) return optfacenum; - else return -optfacenum; - } //end if - - optface = &optimized->faces[optimized->numfaces]; - Com_Memcpy(optface, face, sizeof(aas_face_t)); - - optface->numedges = 0; - optface->firstedge = optimized->edgeindexsize; - for (i = 0; i < face->numedges; i++) - { - edgenum = aasworld.edgeindex[face->firstedge + i]; - optedgenum = AAS_OptimizeEdge(optimized, edgenum); - if (optedgenum) - { - optimized->edgeindex[optface->firstedge + optface->numedges] = optedgenum; - optface->numedges++; - optimized->edgeindexsize++; - } //end if - } //end for - optimized->faceoptimizeindex[abs(facenum)] = optimized->numfaces; - optfacenum = optimized->numfaces; - optimized->numfaces++; - //keep the face side sign - if (facenum > 0) return optfacenum; - else return -optfacenum; -} //end of the function AAS_OptimizeFace -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_OptimizeArea(optimized_t *optimized, int areanum) -{ - int i, facenum, optfacenum; - aas_area_t *area, *optarea; - - area = &aasworld.areas[areanum]; - optarea = &optimized->areas[areanum]; - Com_Memcpy(optarea, area, sizeof(aas_area_t)); - - optarea->numfaces = 0; - optarea->firstface = optimized->faceindexsize; - for (i = 0; i < area->numfaces; i++) - { - facenum = aasworld.faceindex[area->firstface + i]; - optfacenum = AAS_OptimizeFace(optimized, facenum); - if (optfacenum) - { - optimized->faceindex[optarea->firstface + optarea->numfaces] = optfacenum; - optarea->numfaces++; - optimized->faceindexsize++; - } //end if - } //end for -} //end of the function AAS_OptimizeArea -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_OptimizeAlloc(optimized_t *optimized) -{ - optimized->vertexes = (aas_vertex_t *) GetClearedMemory(aasworld.numvertexes * sizeof(aas_vertex_t)); - optimized->numvertexes = 0; - optimized->edges = (aas_edge_t *) GetClearedMemory(aasworld.numedges * sizeof(aas_edge_t)); - optimized->numedges = 1; //edge zero is a dummy - optimized->edgeindex = (aas_edgeindex_t *) GetClearedMemory(aasworld.edgeindexsize * sizeof(aas_edgeindex_t)); - optimized->edgeindexsize = 0; - optimized->faces = (aas_face_t *) GetClearedMemory(aasworld.numfaces * sizeof(aas_face_t)); - optimized->numfaces = 1; //face zero is a dummy - optimized->faceindex = (aas_faceindex_t *) GetClearedMemory(aasworld.faceindexsize * sizeof(aas_faceindex_t)); - optimized->faceindexsize = 0; - optimized->areas = (aas_area_t *) GetClearedMemory(aasworld.numareas * sizeof(aas_area_t)); - optimized->numareas = aasworld.numareas; - // - optimized->vertexoptimizeindex = (int *) GetClearedMemory(aasworld.numvertexes * sizeof(int)); - optimized->edgeoptimizeindex = (int *) GetClearedMemory(aasworld.numedges * sizeof(int)); - optimized->faceoptimizeindex = (int *) GetClearedMemory(aasworld.numfaces * sizeof(int)); -} //end of the function AAS_OptimizeAlloc -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_OptimizeStore(optimized_t *optimized) -{ - //store the optimized vertexes - if (aasworld.vertexes) FreeMemory(aasworld.vertexes); - aasworld.vertexes = optimized->vertexes; - aasworld.numvertexes = optimized->numvertexes; - //store the optimized edges - if (aasworld.edges) FreeMemory(aasworld.edges); - aasworld.edges = optimized->edges; - aasworld.numedges = optimized->numedges; - //store the optimized edge index - if (aasworld.edgeindex) FreeMemory(aasworld.edgeindex); - aasworld.edgeindex = optimized->edgeindex; - aasworld.edgeindexsize = optimized->edgeindexsize; - //store the optimized faces - if (aasworld.faces) FreeMemory(aasworld.faces); - aasworld.faces = optimized->faces; - aasworld.numfaces = optimized->numfaces; - //store the optimized face index - if (aasworld.faceindex) FreeMemory(aasworld.faceindex); - aasworld.faceindex = optimized->faceindex; - aasworld.faceindexsize = optimized->faceindexsize; - //store the optimized areas - if (aasworld.areas) FreeMemory(aasworld.areas); - aasworld.areas = optimized->areas; - aasworld.numareas = optimized->numareas; - //free optimize indexes - FreeMemory(optimized->vertexoptimizeindex); - FreeMemory(optimized->edgeoptimizeindex); - FreeMemory(optimized->faceoptimizeindex); -} //end of the function AAS_OptimizeStore -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_Optimize(void) -{ - int i, sign; - optimized_t optimized; - - AAS_OptimizeAlloc(&optimized); - for (i = 1; i < aasworld.numareas; i++) - { - AAS_OptimizeArea(&optimized, i); - } //end for - //reset the reachability face pointers - for (i = 0; i < aasworld.reachabilitysize; i++) - { - //NOTE: for TRAVEL_ELEVATOR the facenum is the model number of - // the elevator - if ((aasworld.reachability[i].traveltype & TRAVELTYPE_MASK) == TRAVEL_ELEVATOR) continue; - //NOTE: for TRAVEL_JUMPPAD the facenum is the Z velocity and the edgenum is the hor velocity - if ((aasworld.reachability[i].traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMPPAD) continue; - //NOTE: for TRAVEL_FUNCBOB the facenum and edgenum contain other coded information - if ((aasworld.reachability[i].traveltype & TRAVELTYPE_MASK) == TRAVEL_FUNCBOB) continue; - // - sign = aasworld.reachability[i].facenum; - aasworld.reachability[i].facenum = optimized.faceoptimizeindex[abs(aasworld.reachability[i].facenum)]; - if (sign < 0) aasworld.reachability[i].facenum = -aasworld.reachability[i].facenum; - sign = aasworld.reachability[i].edgenum; - aasworld.reachability[i].edgenum = optimized.edgeoptimizeindex[abs(aasworld.reachability[i].edgenum)]; - if (sign < 0) aasworld.reachability[i].edgenum = -aasworld.reachability[i].edgenum; - } //end for - //store the optimized AAS data into aasworld - AAS_OptimizeStore(&optimized); - //print some nice stuff :) - botimport.Print(PRT_MESSAGE, "AAS data optimized.\n"); -} //end of the function AAS_Optimize diff --git a/src/botlib/be_aas_optimize.h b/src/botlib/be_aas_optimize.h deleted file mode 100644 index a6d8916b..00000000 --- a/src/botlib/be_aas_optimize.h +++ /dev/null @@ -1,34 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_aas_optimize.h - * - * desc: AAS - * - * $Archive: /source/code/botlib/be_aas_optimize.h $ - * - *****************************************************************************/ - -void AAS_Optimize(void); - diff --git a/src/botlib/be_aas_reach.c b/src/botlib/be_aas_reach.c deleted file mode 100644 index 1b6d6ab2..00000000 --- a/src/botlib/be_aas_reach.c +++ /dev/null @@ -1,4539 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_aas_reach.c - * - * desc: reachability calculations - * - * $Archive: /MissionPack/code/botlib/be_aas_reach.c $ - * - *****************************************************************************/ - -#include "../qcommon/q_shared.h" -#include "l_log.h" -#include "l_memory.h" -#include "l_script.h" -#include "l_libvar.h" -#include "l_precomp.h" -#include "l_struct.h" -#include "aasfile.h" -#include "botlib.h" -#include "be_aas.h" -#include "be_aas_funcs.h" -#include "be_aas_def.h" - -extern int Sys_MilliSeconds(void); - - -extern botlib_import_t botimport; - -//#define REACH_DEBUG - -//NOTE: all travel times are in hundreth of a second -//maximum number of reachability links -#define AAS_MAX_REACHABILITYSIZE 65536 -//number of areas reachability is calculated for each frame -#define REACHABILITYAREASPERCYCLE 15 -//number of units reachability points are placed inside the areas -#define INSIDEUNITS 2 -#define INSIDEUNITS_WALKEND 5 -#define INSIDEUNITS_WALKSTART 0.1 -#define INSIDEUNITS_WATERJUMP 15 -//area flag used for weapon jumping -#define AREA_WEAPONJUMP 8192 //valid area to weapon jump to -//number of reachabilities of each type -int reach_swim; //swim -int reach_equalfloor; //walk on floors with equal height -int reach_step; //step up -int reach_walk; //walk of step -int reach_barrier; //jump up to a barrier -int reach_waterjump; //jump out of water -int reach_walkoffledge; //walk of a ledge -int reach_jump; //jump -int reach_ladder; //climb or descent a ladder -int reach_teleport; //teleport -int reach_elevator; //use an elevator -int reach_funcbob; //use a func bob -int reach_grapple; //grapple hook -int reach_doublejump; //double jump -int reach_rampjump; //ramp jump -int reach_strafejump; //strafe jump (just normal jump but further) -int reach_rocketjump; //rocket jump -int reach_bfgjump; //bfg jump -int reach_jumppad; //jump pads -//if true grapple reachabilities are skipped -int calcgrapplereach; -//linked reachability -typedef struct aas_lreachability_s -{ - int areanum; //number of the reachable area - int facenum; //number of the face towards the other area - int edgenum; //number of the edge towards the other area - vec3_t start; //start point of inter area movement - vec3_t end; //end point of inter area movement - int traveltype; //type of travel required to get to the area - unsigned short int traveltime; //travel time of the inter area movement - // - struct aas_lreachability_s *next; -} aas_lreachability_t; -//temporary reachabilities -aas_lreachability_t *reachabilityheap; //heap with reachabilities -aas_lreachability_t *nextreachability; //next free reachability from the heap -aas_lreachability_t **areareachability; //reachability links for every area -int numlreachabilities; - -//=========================================================================== -// returns the surface area of the given face -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -float AAS_FaceArea(aas_face_t *face) -{ - int i, edgenum, side; - float total; - vec_t *v; - vec3_t d1, d2, cross; - aas_edge_t *edge; - - edgenum = aasworld.edgeindex[face->firstedge]; - side = edgenum < 0; - edge = &aasworld.edges[abs(edgenum)]; - v = aasworld.vertexes[edge->v[side]]; - - total = 0; - for (i = 1; i < face->numedges - 1; i++) - { - edgenum = aasworld.edgeindex[face->firstedge + i]; - side = edgenum < 0; - edge = &aasworld.edges[abs(edgenum)]; - VectorSubtract(aasworld.vertexes[edge->v[side]], v, d1); - VectorSubtract(aasworld.vertexes[edge->v[!side]], v, d2); - CrossProduct(d1, d2, cross); - total += 0.5 * VectorLength(cross); - } //end for - return total; -} //end of the function AAS_FaceArea -//=========================================================================== -// returns the volume of an area -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -float AAS_AreaVolume(int areanum) -{ - int i, edgenum, facenum, side; - vec_t d, a, volume; - vec3_t corner; - aas_plane_t *plane; - aas_edge_t *edge; - aas_face_t *face; - aas_area_t *area; - - area = &aasworld.areas[areanum]; - facenum = aasworld.faceindex[area->firstface]; - face = &aasworld.faces[abs(facenum)]; - edgenum = aasworld.edgeindex[face->firstedge]; - edge = &aasworld.edges[abs(edgenum)]; - // - VectorCopy(aasworld.vertexes[edge->v[0]], corner); - - //make tetrahedrons to all other faces - volume = 0; - for (i = 0; i < area->numfaces; i++) - { - facenum = abs(aasworld.faceindex[area->firstface + i]); - face = &aasworld.faces[facenum]; - side = face->backarea != areanum; - plane = &aasworld.planes[face->planenum ^ side]; - d = -(DotProduct (corner, plane->normal) - plane->dist); - a = AAS_FaceArea(face); - volume += d * a; - } //end for - - volume /= 3; - return volume; -} //end of the function AAS_AreaVolume -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_BestReachableLinkArea(aas_link_t *areas) -{ - aas_link_t *link; - - for (link = areas; link; link = link->next_area) - { - if (AAS_AreaGrounded(link->areanum) || AAS_AreaSwim(link->areanum)) - { - return link->areanum; - } //end if - } //end for - // - for (link = areas; link; link = link->next_area) - { - if (link->areanum) return link->areanum; - //FIXME: this is a bad idea when the reachability is not yet - // calculated when the level items are loaded - if (AAS_AreaReachability(link->areanum)) - return link->areanum; - } //end for - return 0; -} //end of the function AAS_BestReachableLinkArea -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_GetJumpPadInfo(int ent, vec3_t areastart, vec3_t absmins, vec3_t absmaxs, vec3_t velocity) -{ - int modelnum, ent2; - float speed, height, gravity, time, dist, forward; - vec3_t origin, angles, teststart, ent2origin; - aas_trace_t trace; - char model[MAX_EPAIRKEY]; - char target[MAX_EPAIRKEY], targetname[MAX_EPAIRKEY]; - - // - AAS_FloatForBSPEpairKey(ent, "speed", &speed); - if (!speed) speed = 1000; - VectorClear(angles); - //get the mins, maxs and origin of the model - AAS_ValueForBSPEpairKey(ent, "model", model, MAX_EPAIRKEY); - if (model[0]) modelnum = atoi(model+1); - else modelnum = 0; - AAS_BSPModelMinsMaxsOrigin(modelnum, angles, absmins, absmaxs, origin); - VectorAdd(origin, absmins, absmins); - VectorAdd(origin, absmaxs, absmaxs); - VectorAdd(absmins, absmaxs, origin); - VectorScale (origin, 0.5, origin); - - //get the start areas - VectorCopy(origin, teststart); - teststart[2] += 64; - trace = AAS_TraceClientBBox(teststart, origin, PRESENCE_CROUCH, -1); - if (trace.startsolid) - { - botimport.Print(PRT_MESSAGE, "trigger_push start solid\n"); - VectorCopy(origin, areastart); - } //end if - else - { - VectorCopy(trace.endpos, areastart); - } //end else - areastart[2] += 0.125; - // - //AAS_DrawPermanentCross(origin, 4, 4); - //get the target entity - AAS_ValueForBSPEpairKey(ent, "target", target, MAX_EPAIRKEY); - for (ent2 = AAS_NextBSPEntity(0); ent2; ent2 = AAS_NextBSPEntity(ent2)) - { - if (!AAS_ValueForBSPEpairKey(ent2, "targetname", targetname, MAX_EPAIRKEY)) continue; - if (!strcmp(targetname, target)) break; - } //end for - if (!ent2) - { - botimport.Print(PRT_MESSAGE, "trigger_push without target entity %s\n", target); - return qfalse; - } //end if - AAS_VectorForBSPEpairKey(ent2, "origin", ent2origin); - // - height = ent2origin[2] - origin[2]; - gravity = aassettings.phys_gravity; - time = sqrt( height / ( 0.5 * gravity ) ); - if (!time) - { - botimport.Print(PRT_MESSAGE, "trigger_push without time\n"); - return qfalse; - } //end if - // set s.origin2 to the push velocity - VectorSubtract ( ent2origin, origin, velocity); - dist = VectorNormalize( velocity); - forward = dist / time; - //FIXME: why multiply by 1.1 - forward *= 1.1f; - VectorScale(velocity, forward, velocity); - velocity[2] = time * gravity; - return qtrue; -} //end of the function AAS_GetJumpPadInfo -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_BestReachableFromJumpPadArea(vec3_t origin, vec3_t mins, vec3_t maxs) -{ - int area2num, ent, bot_visualizejumppads, bestareanum; - float volume, bestareavolume; - vec3_t areastart, cmdmove, bboxmins, bboxmaxs; - vec3_t absmins, absmaxs, velocity; - aas_clientmove_t move; - aas_link_t *areas, *link; - char classname[MAX_EPAIRKEY]; - -#ifdef BSPC - bot_visualizejumppads = 0; -#else - bot_visualizejumppads = LibVarValue("bot_visualizejumppads", "0"); -#endif - VectorAdd(origin, mins, bboxmins); - VectorAdd(origin, maxs, bboxmaxs); - for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent)) - { - if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue; - if (strcmp(classname, "trigger_push")) continue; - // - if (!AAS_GetJumpPadInfo(ent, areastart, absmins, absmaxs, velocity)) continue; - //get the areas the jump pad brush is in - areas = AAS_LinkEntityClientBBox(absmins, absmaxs, -1, PRESENCE_CROUCH); - for (link = areas; link; link = link->next_area) - { - if (AAS_AreaJumpPad(link->areanum)) break; - } //end for - if (!link) - { - botimport.Print(PRT_MESSAGE, "trigger_push not in any jump pad area\n"); - AAS_UnlinkFromAreas(areas); - continue; - } //end if - // - //botimport.Print(PRT_MESSAGE, "found a trigger_push with velocity %f %f %f\n", velocity[0], velocity[1], velocity[2]); - // - VectorSet(cmdmove, 0, 0, 0); - Com_Memset(&move, 0, sizeof(aas_clientmove_t)); - area2num = 0; - AAS_ClientMovementHitBBox(&move, -1, areastart, PRESENCE_NORMAL, qfalse, - velocity, cmdmove, 0, 30, 0.1f, bboxmins, bboxmaxs, bot_visualizejumppads); - if (move.frames < 30) - { - bestareanum = 0; - bestareavolume = 0; - for (link = areas; link; link = link->next_area) - { - if (!AAS_AreaJumpPad(link->areanum)) continue; - volume = AAS_AreaVolume(link->areanum); - if (volume >= bestareavolume) - { - bestareanum = link->areanum; - bestareavolume = volume; - } //end if - } //end if - AAS_UnlinkFromAreas(areas); - return bestareanum; - } //end if - AAS_UnlinkFromAreas(areas); - } //end for - return 0; -} //end of the function AAS_BestReachableFromJumpPadArea -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_BestReachableArea(vec3_t origin, vec3_t mins, vec3_t maxs, vec3_t goalorigin) -{ - int areanum, i, j, k, l; - aas_link_t *areas; - vec3_t absmins, absmaxs; - //vec3_t bbmins, bbmaxs; - vec3_t start, end; - aas_trace_t trace; - - if (!aasworld.loaded) - { - botimport.Print(PRT_ERROR, "AAS_BestReachableArea: aas not loaded\n"); - return 0; - } //end if - //find a point in an area - VectorCopy(origin, start); - areanum = AAS_PointAreaNum(start); - //while no area found fudge around a little - for (i = 0; i < 5 && !areanum; i++) - { - for (j = 0; j < 5 && !areanum; j++) - { - for (k = -1; k <= 1 && !areanum; k++) - { - for (l = -1; l <= 1 && !areanum; l++) - { - VectorCopy(origin, start); - start[0] += (float) j * 4 * k; - start[1] += (float) j * 4 * l; - start[2] += (float) i * 4; - areanum = AAS_PointAreaNum(start); - } //end for - } //end for - } //end for - } //end for - //if an area was found - if (areanum) - { - //drop client bbox down and try again - VectorCopy(start, end); - start[2] += 0.25; - end[2] -= 50; - trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, -1); - if (!trace.startsolid) - { - areanum = AAS_PointAreaNum(trace.endpos); - VectorCopy(trace.endpos, goalorigin); - //FIXME: cannot enable next line right now because the reachability - // does not have to be calculated when the level items are loaded - //if the origin is in an area with reachability - //if (AAS_AreaReachability(areanum)) return areanum; - if (areanum) return areanum; - } //end if - else - { - //it can very well happen that the AAS_PointAreaNum function tells that - //a point is in an area and that starting a AAS_TraceClientBBox from that - //point will return trace.startsolid qtrue -#if 0 - if (AAS_PointAreaNum(start)) - { - Log_Write("point %f %f %f in area %d but trace startsolid", start[0], start[1], start[2], areanum); - AAS_DrawPermanentCross(start, 4, LINECOLOR_RED); - } //end if - botimport.Print(PRT_MESSAGE, "AAS_BestReachableArea: start solid\n"); -#endif - VectorCopy(start, goalorigin); - return areanum; - } //end else - } //end if - // - //AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, bbmins, bbmaxs); - //NOTE: the goal origin does not have to be in the goal area - // because the bot will have to move towards the item origin anyway - VectorCopy(origin, goalorigin); - // - VectorAdd(origin, mins, absmins); - VectorAdd(origin, maxs, absmaxs); - //add bounding box size - //VectorSubtract(absmins, bbmaxs, absmins); - //VectorSubtract(absmaxs, bbmins, absmaxs); - //link an invalid (-1) entity - areas = AAS_LinkEntityClientBBox(absmins, absmaxs, -1, PRESENCE_CROUCH); - //get the reachable link arae - areanum = AAS_BestReachableLinkArea(areas); - //unlink the invalid entity - AAS_UnlinkFromAreas(areas); - // - return areanum; -} //end of the function AAS_BestReachableArea -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_SetupReachabilityHeap(void) -{ - int i; - - reachabilityheap = (aas_lreachability_t *) GetClearedMemory( - AAS_MAX_REACHABILITYSIZE * sizeof(aas_lreachability_t)); - for (i = 0; i < AAS_MAX_REACHABILITYSIZE-1; i++) - { - reachabilityheap[i].next = &reachabilityheap[i+1]; - } //end for - reachabilityheap[AAS_MAX_REACHABILITYSIZE-1].next = NULL; - nextreachability = reachabilityheap; - numlreachabilities = 0; -} //end of the function AAS_InitReachabilityHeap -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_ShutDownReachabilityHeap(void) -{ - FreeMemory(reachabilityheap); - numlreachabilities = 0; -} //end of the function AAS_ShutDownReachabilityHeap -//=========================================================================== -// returns a reachability link -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -aas_lreachability_t *AAS_AllocReachability(void) -{ - aas_lreachability_t *r; - - if (!nextreachability) return NULL; - //make sure the error message only shows up once - if (!nextreachability->next) AAS_Error("AAS_MAX_REACHABILITYSIZE"); - // - r = nextreachability; - nextreachability = nextreachability->next; - numlreachabilities++; - return r; -} //end of the function AAS_AllocReachability -//=========================================================================== -// frees a reachability link -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_FreeReachability(aas_lreachability_t *lreach) -{ - Com_Memset(lreach, 0, sizeof(aas_lreachability_t)); - - lreach->next = nextreachability; - nextreachability = lreach; - numlreachabilities--; -} //end of the function AAS_FreeReachability -//=========================================================================== -// returns qtrue if the area has reachability links -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_AreaReachability(int areanum) -{ - if (areanum < 0 || areanum >= aasworld.numareas) - { - AAS_Error("AAS_AreaReachability: areanum %d out of range", areanum); - return 0; - } //end if - return aasworld.areasettings[areanum].numreachableareas; -} //end of the function AAS_AreaReachability -//=========================================================================== -// returns the surface area of all ground faces together of the area -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -float AAS_AreaGroundFaceArea(int areanum) -{ - int i; - float total; - aas_area_t *area; - aas_face_t *face; - - total = 0; - area = &aasworld.areas[areanum]; - for (i = 0; i < area->numfaces; i++) - { - face = &aasworld.faces[abs(aasworld.faceindex[area->firstface + i])]; - if (!(face->faceflags & FACE_GROUND)) continue; - // - total += AAS_FaceArea(face); - } //end for - return total; -} //end of the function AAS_AreaGroundFaceArea -//=========================================================================== -// returns the center of a face -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_FaceCenter(int facenum, vec3_t center) -{ - int i; - float scale; - aas_face_t *face; - aas_edge_t *edge; - - face = &aasworld.faces[facenum]; - - VectorClear(center); - for (i = 0; i < face->numedges; i++) - { - edge = &aasworld.edges[abs(aasworld.edgeindex[face->firstedge + i])]; - VectorAdd(center, aasworld.vertexes[edge->v[0]], center); - VectorAdd(center, aasworld.vertexes[edge->v[1]], center); - } //end for - scale = 0.5 / face->numedges; - VectorScale(center, scale, center); -} //end of the function AAS_FaceCenter -//=========================================================================== -// returns the maximum distance a player can fall before being damaged -// damage = deltavelocity*deltavelocity * 0.0001 -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_FallDamageDistance(void) -{ - float maxzvelocity, gravity, t; - - maxzvelocity = sqrt(30 * 10000); - gravity = aassettings.phys_gravity; - t = maxzvelocity / gravity; - return 0.5 * gravity * t * t; -} //end of the function AAS_FallDamageDistance -//=========================================================================== -// distance = 0.5 * gravity * t * t -// vel = t * gravity -// damage = vel * vel * 0.0001 -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -float AAS_FallDelta(float distance) -{ - float t, delta, gravity; - - gravity = aassettings.phys_gravity; - t = sqrt(fabs(distance) * 2 / gravity); - delta = t * gravity; - return delta * delta * 0.0001; -} //end of the function AAS_FallDelta -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -float AAS_MaxJumpHeight(float phys_jumpvel) -{ - float phys_gravity; - - phys_gravity = aassettings.phys_gravity; - //maximum height a player can jump with the given initial z velocity - return 0.5 * phys_gravity * (phys_jumpvel / phys_gravity) * (phys_jumpvel / phys_gravity); -} //end of the function MaxJumpHeight -//=========================================================================== -// returns true if a player can only crouch in the area -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -float AAS_MaxJumpDistance(float phys_jumpvel) -{ - float phys_gravity, phys_maxvelocity, t; - - phys_gravity = aassettings.phys_gravity; - phys_maxvelocity = aassettings.phys_maxvelocity; - //time a player takes to fall the height - t = sqrt(aassettings.rs_maxjumpfallheight / (0.5 * phys_gravity)); - //maximum distance - return phys_maxvelocity * (t + phys_jumpvel / phys_gravity); -} //end of the function AAS_MaxJumpDistance -//=========================================================================== -// returns true if a player can only crouch in the area -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_AreaCrouch(int areanum) -{ - if (!(aasworld.areasettings[areanum].presencetype & PRESENCE_NORMAL)) return qtrue; - else return qfalse; -} //end of the function AAS_AreaCrouch -//=========================================================================== -// returns qtrue if it is possible to swim in the area -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_AreaSwim(int areanum) -{ - if (aasworld.areasettings[areanum].areaflags & AREA_LIQUID) return qtrue; - else return qfalse; -} //end of the function AAS_AreaSwim -//=========================================================================== -// returns qtrue if the area contains a liquid -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_AreaLiquid(int areanum) -{ - if (aasworld.areasettings[areanum].areaflags & AREA_LIQUID) return qtrue; - else return qfalse; -} //end of the function AAS_AreaLiquid -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_AreaLava(int areanum) -{ - return (aasworld.areasettings[areanum].contents & AREACONTENTS_LAVA); -} //end of the function AAS_AreaLava -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_AreaSlime(int areanum) -{ - return (aasworld.areasettings[areanum].contents & AREACONTENTS_SLIME); -} //end of the function AAS_AreaSlime -//=========================================================================== -// returns qtrue if the area contains ground faces -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_AreaGrounded(int areanum) -{ - return (aasworld.areasettings[areanum].areaflags & AREA_GROUNDED); -} //end of the function AAS_AreaGround -//=========================================================================== -// returns true if the area contains ladder faces -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_AreaLadder(int areanum) -{ - return (aasworld.areasettings[areanum].areaflags & AREA_LADDER); -} //end of the function AAS_AreaLadder -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_AreaJumpPad(int areanum) -{ - return (aasworld.areasettings[areanum].contents & AREACONTENTS_JUMPPAD); -} //end of the function AAS_AreaJumpPad -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_AreaTeleporter(int areanum) -{ - return (aasworld.areasettings[areanum].contents & AREACONTENTS_TELEPORTER); -} //end of the function AAS_AreaTeleporter -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_AreaClusterPortal(int areanum) -{ - return (aasworld.areasettings[areanum].contents & AREACONTENTS_CLUSTERPORTAL); -} //end of the function AAS_AreaClusterPortal -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_AreaDoNotEnter(int areanum) -{ - return (aasworld.areasettings[areanum].contents & AREACONTENTS_DONOTENTER); -} //end of the function AAS_AreaDoNotEnter -//=========================================================================== -// returns the time it takes perform a barrier jump -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -unsigned short int AAS_BarrierJumpTravelTime(void) -{ - return aassettings.phys_jumpvel / (aassettings.phys_gravity * 0.1); -} //end op the function AAS_BarrierJumpTravelTime -//=========================================================================== -// returns true if there already exists a reachability from area1 to area2 -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -qboolean AAS_ReachabilityExists(int area1num, int area2num) -{ - aas_lreachability_t *r; - - for (r = areareachability[area1num]; r; r = r->next) - { - if (r->areanum == area2num) return qtrue; - } //end for - return qfalse; -} //end of the function AAS_ReachabilityExists -//=========================================================================== -// returns true if there is a solid just after the end point when going -// from start to end -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_NearbySolidOrGap(vec3_t start, vec3_t end) -{ - vec3_t dir, testpoint; - int areanum; - - VectorSubtract(end, start, dir); - dir[2] = 0; - VectorNormalize(dir); - VectorMA(end, 48, dir, testpoint); - - areanum = AAS_PointAreaNum(testpoint); - if (!areanum) - { - testpoint[2] += 16; - areanum = AAS_PointAreaNum(testpoint); - if (!areanum) return qtrue; - } //end if - VectorMA(end, 64, dir, testpoint); - areanum = AAS_PointAreaNum(testpoint); - if (areanum) - { - if (!AAS_AreaSwim(areanum) && !AAS_AreaGrounded(areanum)) return qtrue; - } //end if - return qfalse; -} //end of the function AAS_SolidGapTime -//=========================================================================== -// searches for swim reachabilities between adjacent areas -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_Reachability_Swim(int area1num, int area2num) -{ - int i, j, face1num, face2num, side1; - aas_area_t *area1, *area2; - aas_areasettings_t *areasettings; - aas_lreachability_t *lreach; - aas_face_t *face1; - aas_plane_t *plane; - vec3_t start; - - if (!AAS_AreaSwim(area1num) || !AAS_AreaSwim(area2num)) return qfalse; - //if the second area is crouch only - if (!(aasworld.areasettings[area2num].presencetype & PRESENCE_NORMAL)) return qfalse; - - area1 = &aasworld.areas[area1num]; - area2 = &aasworld.areas[area2num]; - - //if the areas are not near anough - for (i = 0; i < 3; i++) - { - if (area1->mins[i] > area2->maxs[i] + 10) return qfalse; - if (area1->maxs[i] < area2->mins[i] - 10) return qfalse; - } //end for - //find a shared face and create a reachability link - for (i = 0; i < area1->numfaces; i++) - { - face1num = aasworld.faceindex[area1->firstface + i]; - side1 = face1num < 0; - face1num = abs(face1num); - // - for (j = 0; j < area2->numfaces; j++) - { - face2num = abs(aasworld.faceindex[area2->firstface + j]); - // - if (face1num == face2num) - { - AAS_FaceCenter(face1num, start); - // - if (AAS_PointContents(start) & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER)) - { - // - face1 = &aasworld.faces[face1num]; - areasettings = &aasworld.areasettings[area1num]; - //create a new reachability link - lreach = AAS_AllocReachability(); - if (!lreach) return qfalse; - lreach->areanum = area2num; - lreach->facenum = face1num; - lreach->edgenum = 0; - VectorCopy(start, lreach->start); - plane = &aasworld.planes[face1->planenum ^ side1]; - VectorMA(lreach->start, -INSIDEUNITS, plane->normal, lreach->end); - lreach->traveltype = TRAVEL_SWIM; - lreach->traveltime = 1; - //if the volume of the area is rather small - if (AAS_AreaVolume(area2num) < 800) - lreach->traveltime += 200; - //if (!(AAS_PointContents(start) & MASK_WATER)) lreach->traveltime += 500; - //link the reachability - lreach->next = areareachability[area1num]; - areareachability[area1num] = lreach; - reach_swim++; - return qtrue; - } //end if - } //end if - } //end for - } //end for - return qfalse; -} //end of the function AAS_Reachability_Swim -//=========================================================================== -// searches for reachabilities between adjacent areas with equal floor -// heights -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_Reachability_EqualFloorHeight(int area1num, int area2num) -{ - int i, j, edgenum, edgenum1, edgenum2, foundreach, side; - float height, bestheight, length, bestlength; - vec3_t dir, start, end, normal, invgravity, gravitydirection = {0, 0, -1}; - vec3_t edgevec; - aas_area_t *area1, *area2; - aas_face_t *face1, *face2; - aas_edge_t *edge; - aas_plane_t *plane2; - aas_lreachability_t lr, *lreach; - - if (!AAS_AreaGrounded(area1num) || !AAS_AreaGrounded(area2num)) return qfalse; - - area1 = &aasworld.areas[area1num]; - area2 = &aasworld.areas[area2num]; - //if the areas are not near anough in the x-y direction - for (i = 0; i < 2; i++) - { - if (area1->mins[i] > area2->maxs[i] + 10) return qfalse; - if (area1->maxs[i] < area2->mins[i] - 10) return qfalse; - } //end for - //if area 2 is too high above area 1 - if (area2->mins[2] > area1->maxs[2]) return qfalse; - // - VectorCopy(gravitydirection, invgravity); - VectorInverse(invgravity); - // - bestheight = 99999; - bestlength = 0; - foundreach = qfalse; - Com_Memset(&lr, 0, sizeof(aas_lreachability_t)); //make the compiler happy - // - //check if the areas have ground faces with a common edge - //if existing use the lowest common edge for a reachability link - for (i = 0; i < area1->numfaces; i++) - { - face1 = &aasworld.faces[abs(aasworld.faceindex[area1->firstface + i])]; - if (!(face1->faceflags & FACE_GROUND)) continue; - // - for (j = 0; j < area2->numfaces; j++) - { - face2 = &aasworld.faces[abs(aasworld.faceindex[area2->firstface + j])]; - if (!(face2->faceflags & FACE_GROUND)) continue; - //if there is a common edge - for (edgenum1 = 0; edgenum1 < face1->numedges; edgenum1++) - { - for (edgenum2 = 0; edgenum2 < face2->numedges; edgenum2++) - { - if (abs(aasworld.edgeindex[face1->firstedge + edgenum1]) != - abs(aasworld.edgeindex[face2->firstedge + edgenum2])) - continue; - edgenum = aasworld.edgeindex[face1->firstedge + edgenum1]; - side = edgenum < 0; - edge = &aasworld.edges[abs(edgenum)]; - //get the length of the edge - VectorSubtract(aasworld.vertexes[edge->v[1]], - aasworld.vertexes[edge->v[0]], dir); - length = VectorLength(dir); - //get the start point - VectorAdd(aasworld.vertexes[edge->v[0]], - aasworld.vertexes[edge->v[1]], start); - VectorScale(start, 0.5, start); - VectorCopy(start, end); - //get the end point several units inside area2 - //and the start point several units inside area1 - //NOTE: normal is pointing into area2 because the - //face edges are stored counter clockwise - VectorSubtract(aasworld.vertexes[edge->v[side]], - aasworld.vertexes[edge->v[!side]], edgevec); - plane2 = &aasworld.planes[face2->planenum]; - CrossProduct(edgevec, plane2->normal, normal); - VectorNormalize(normal); - // - //VectorMA(start, -1, normal, start); - VectorMA(end, INSIDEUNITS_WALKEND, normal, end); - VectorMA(start, INSIDEUNITS_WALKSTART, normal, start); - end[2] += 0.125; - // - height = DotProduct(invgravity, start); - //NOTE: if there's nearby solid or a gap area after this area - //disabled this crap - //if (AAS_NearbySolidOrGap(start, end)) height += 200; - //NOTE: disabled because it disables reachabilities to very small areas - //if (AAS_PointAreaNum(end) != area2num) continue; - //get the longest lowest edge - if (height < bestheight || - (height < bestheight + 1 && length > bestlength)) - { - bestheight = height; - bestlength = length; - //create a new reachability link - lr.areanum = area2num; - lr.facenum = 0; - lr.edgenum = edgenum; - VectorCopy(start, lr.start); - VectorCopy(end, lr.end); - lr.traveltype = TRAVEL_WALK; - lr.traveltime = 1; - foundreach = qtrue; - } //end if - } //end for - } //end for - } //end for - } //end for - if (foundreach) - { - //create a new reachability link - lreach = AAS_AllocReachability(); - if (!lreach) return qfalse; - lreach->areanum = lr.areanum; - lreach->facenum = lr.facenum; - lreach->edgenum = lr.edgenum; - VectorCopy(lr.start, lreach->start); - VectorCopy(lr.end, lreach->end); - lreach->traveltype = lr.traveltype; - lreach->traveltime = lr.traveltime; - lreach->next = areareachability[area1num]; - areareachability[area1num] = lreach; - //if going into a crouch area - if (!AAS_AreaCrouch(area1num) && AAS_AreaCrouch(area2num)) - { - lreach->traveltime += aassettings.rs_startcrouch; - } //end if - /* - //NOTE: if there's nearby solid or a gap area after this area - if (!AAS_NearbySolidOrGap(lreach->start, lreach->end)) - { - lreach->traveltime += 100; - } //end if - */ - //avoid rather small areas - //if (AAS_AreaGroundFaceArea(lreach->areanum) < 500) lreach->traveltime += 100; - // - reach_equalfloor++; - return qtrue; - } //end if - return qfalse; -} //end of the function AAS_Reachability_EqualFloorHeight -//=========================================================================== -// searches step, barrier, waterjump and walk off ledge reachabilities -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_Reachability_Step_Barrier_WaterJump_WalkOffLedge(int area1num, int area2num) -{ - int i, j, k, l, edge1num, edge2num, areas[10], numareas; - int ground_bestarea2groundedgenum, ground_foundreach; - int water_bestarea2groundedgenum, water_foundreach; - int side1, area1swim, faceside1, groundface1num; - float dist, dist1, dist2, diff, invgravitydot, ortdot; - float x1, x2, x3, x4, y1, y2, y3, y4, tmp, y; - float length, ground_bestlength, water_bestlength, ground_bestdist, water_bestdist; - vec3_t v1, v2, v3, v4, tmpv, p1area1, p1area2, p2area1, p2area2; - vec3_t normal, ort, edgevec, start, end, dir; - vec3_t ground_beststart = {0, 0, 0}, ground_bestend = {0, 0, 0}, ground_bestnormal = {0, 0, 0}; - vec3_t water_beststart = {0, 0, 0}, water_bestend = {0, 0, 0}, water_bestnormal = {0, 0, 0}; - vec3_t invgravity = {0, 0, 1}; - vec3_t testpoint; - aas_plane_t *plane; - aas_area_t *area1, *area2; - aas_face_t *groundface1, *groundface2, *ground_bestface1, *water_bestface1; - aas_edge_t *edge1, *edge2; - aas_lreachability_t *lreach; - aas_trace_t trace; - - //must be able to walk or swim in the first area - if (!AAS_AreaGrounded(area1num) && !AAS_AreaSwim(area1num)) return qfalse; - // - if (!AAS_AreaGrounded(area2num) && !AAS_AreaSwim(area2num)) return qfalse; - // - area1 = &aasworld.areas[area1num]; - area2 = &aasworld.areas[area2num]; - //if the first area contains a liquid - area1swim = AAS_AreaSwim(area1num); - //if the areas are not near anough in the x-y direction - for (i = 0; i < 2; i++) - { - if (area1->mins[i] > area2->maxs[i] + 10) return qfalse; - if (area1->maxs[i] < area2->mins[i] - 10) return qfalse; - } //end for - // - ground_foundreach = qfalse; - ground_bestdist = 99999; - ground_bestlength = 0; - ground_bestarea2groundedgenum = 0; - // - water_foundreach = qfalse; - water_bestdist = 99999; - water_bestlength = 0; - water_bestarea2groundedgenum = 0; - // - for (i = 0; i < area1->numfaces; i++) - { - groundface1num = aasworld.faceindex[area1->firstface + i]; - faceside1 = groundface1num < 0; - groundface1 = &aasworld.faces[abs(groundface1num)]; - //if this isn't a ground face - if (!(groundface1->faceflags & FACE_GROUND)) - { - //if we can swim in the first area - if (area1swim) - { - //face plane must be more or less horizontal - plane = &aasworld.planes[groundface1->planenum ^ (!faceside1)]; - if (DotProduct(plane->normal, invgravity) < 0.7) continue; - } //end if - else - { - //if we can't swim in the area it must be a ground face - continue; - } //end else - } //end if - // - for (k = 0; k < groundface1->numedges; k++) - { - edge1num = aasworld.edgeindex[groundface1->firstedge + k]; - side1 = (edge1num < 0); - //NOTE: for water faces we must take the side area 1 is - // on into account because the face is shared and doesn't - // have to be oriented correctly - if (!(groundface1->faceflags & FACE_GROUND)) side1 = (side1 == faceside1); - edge1num = abs(edge1num); - edge1 = &aasworld.edges[edge1num]; - //vertexes of the edge - VectorCopy(aasworld.vertexes[edge1->v[!side1]], v1); - VectorCopy(aasworld.vertexes[edge1->v[side1]], v2); - //get a vertical plane through the edge - //NOTE: normal is pointing into area 2 because the - //face edges are stored counter clockwise - VectorSubtract(v2, v1, edgevec); - CrossProduct(edgevec, invgravity, normal); - VectorNormalize(normal); - dist = DotProduct(normal, v1); - //check the faces from the second area - for (j = 0; j < area2->numfaces; j++) - { - groundface2 = &aasworld.faces[abs(aasworld.faceindex[area2->firstface + j])]; - //must be a ground face - if (!(groundface2->faceflags & FACE_GROUND)) continue; - //check the edges of this ground face - for (l = 0; l < groundface2->numedges; l++) - { - edge2num = abs(aasworld.edgeindex[groundface2->firstedge + l]); - edge2 = &aasworld.edges[edge2num]; - //vertexes of the edge - VectorCopy(aasworld.vertexes[edge2->v[0]], v3); - VectorCopy(aasworld.vertexes[edge2->v[1]], v4); - //check the distance between the two points and the vertical plane - //through the edge of area1 - diff = DotProduct(normal, v3) - dist; - if (diff < -0.1 || diff > 0.1) continue; - diff = DotProduct(normal, v4) - dist; - if (diff < -0.1 || diff > 0.1) continue; - // - //project the two ground edges into the step side plane - //and calculate the shortest distance between the two - //edges if they overlap in the direction orthogonal to - //the gravity direction - CrossProduct(invgravity, normal, ort); - invgravitydot = DotProduct(invgravity, invgravity); - ortdot = DotProduct(ort, ort); - //projection into the step plane - //NOTE: since gravity is vertical this is just the z coordinate - y1 = v1[2];//DotProduct(v1, invgravity) / invgravitydot; - y2 = v2[2];//DotProduct(v2, invgravity) / invgravitydot; - y3 = v3[2];//DotProduct(v3, invgravity) / invgravitydot; - y4 = v4[2];//DotProduct(v4, invgravity) / invgravitydot; - // - x1 = DotProduct(v1, ort) / ortdot; - x2 = DotProduct(v2, ort) / ortdot; - x3 = DotProduct(v3, ort) / ortdot; - x4 = DotProduct(v4, ort) / ortdot; - // - if (x1 > x2) - { - tmp = x1; x1 = x2; x2 = tmp; - tmp = y1; y1 = y2; y2 = tmp; - VectorCopy(v1, tmpv); VectorCopy(v2, v1); VectorCopy(tmpv, v2); - } //end if - if (x3 > x4) - { - tmp = x3; x3 = x4; x4 = tmp; - tmp = y3; y3 = y4; y4 = tmp; - VectorCopy(v3, tmpv); VectorCopy(v4, v3); VectorCopy(tmpv, v4); - } //end if - //if the two projected edge lines have no overlap - if (x2 <= x3 || x4 <= x1) - { -// Log_Write("lines no overlap: from area %d to %d\r\n", area1num, area2num); - continue; - } //end if - //if the two lines fully overlap - if ((x1 - 0.5 < x3 && x4 < x2 + 0.5) && - (x3 - 0.5 < x1 && x2 < x4 + 0.5)) - { - dist1 = y3 - y1; - dist2 = y4 - y2; - VectorCopy(v1, p1area1); - VectorCopy(v2, p2area1); - VectorCopy(v3, p1area2); - VectorCopy(v4, p2area2); - } //end if - else - { - //if the points are equal - if (x1 > x3 - 0.1 && x1 < x3 + 0.1) - { - dist1 = y3 - y1; - VectorCopy(v1, p1area1); - VectorCopy(v3, p1area2); - } //end if - else if (x1 < x3) - { - y = y1 + (x3 - x1) * (y2 - y1) / (x2 - x1); - dist1 = y3 - y; - VectorCopy(v3, p1area1); - p1area1[2] = y; - VectorCopy(v3, p1area2); - } //end if - else - { - y = y3 + (x1 - x3) * (y4 - y3) / (x4 - x3); - dist1 = y - y1; - VectorCopy(v1, p1area1); - VectorCopy(v1, p1area2); - p1area2[2] = y; - } //end if - //if the points are equal - if (x2 > x4 - 0.1 && x2 < x4 + 0.1) - { - dist2 = y4 - y2; - VectorCopy(v2, p2area1); - VectorCopy(v4, p2area2); - } //end if - else if (x2 < x4) - { - y = y3 + (x2 - x3) * (y4 - y3) / (x4 - x3); - dist2 = y - y2; - VectorCopy(v2, p2area1); - VectorCopy(v2, p2area2); - p2area2[2] = y; - } //end if - else - { - y = y1 + (x4 - x1) * (y2 - y1) / (x2 - x1); - dist2 = y4 - y; - VectorCopy(v4, p2area1); - p2area1[2] = y; - VectorCopy(v4, p2area2); - } //end else - } //end else - //if both distances are pretty much equal - //then we take the middle of the points - if (dist1 > dist2 - 1 && dist1 < dist2 + 1) - { - dist = dist1; - VectorAdd(p1area1, p2area1, start); - VectorScale(start, 0.5, start); - VectorAdd(p1area2, p2area2, end); - VectorScale(end, 0.5, end); - } //end if - else if (dist1 < dist2) - { - dist = dist1; - VectorCopy(p1area1, start); - VectorCopy(p1area2, end); - } //end else if - else - { - dist = dist2; - VectorCopy(p2area1, start); - VectorCopy(p2area2, end); - } //end else - //get the length of the overlapping part of the edges of the two areas - VectorSubtract(p2area2, p1area2, dir); - length = VectorLength(dir); - // - if (groundface1->faceflags & FACE_GROUND) - { - //if the vertical distance is smaller - if (dist < ground_bestdist || - //or the vertical distance is pretty much the same - //but the overlapping part of the edges is longer - (dist < ground_bestdist + 1 && length > ground_bestlength)) - { - ground_bestdist = dist; - ground_bestlength = length; - ground_foundreach = qtrue; - ground_bestarea2groundedgenum = edge1num; - ground_bestface1 = groundface1; - //best point towards area1 - VectorCopy(start, ground_beststart); - //normal is pointing into area2 - VectorCopy(normal, ground_bestnormal); - //best point towards area2 - VectorCopy(end, ground_bestend); - } //end if - } //end if - else - { - //if the vertical distance is smaller - if (dist < water_bestdist || - //or the vertical distance is pretty much the same - //but the overlapping part of the edges is longer - (dist < water_bestdist + 1 && length > water_bestlength)) - { - water_bestdist = dist; - water_bestlength = length; - water_foundreach = qtrue; - water_bestarea2groundedgenum = edge1num; - water_bestface1 = groundface1; - //best point towards area1 - VectorCopy(start, water_beststart); - //normal is pointing into area2 - VectorCopy(normal, water_bestnormal); - //best point towards area2 - VectorCopy(end, water_bestend); - } //end if - } //end else - } //end for - } //end for - } //end for - } //end for - // - // NOTE: swim reachabilities are already filtered out - // - // Steps - // - // --------- - // | step height -> TRAVEL_WALK - //--------| - // - // --------- - //~~~~~~~~| step height and low water -> TRAVEL_WALK - //--------| - // - //~~~~~~~~~~~~~~~~~~ - // --------- - // | step height and low water up to the step -> TRAVEL_WALK - //--------| - // - //check for a step reachability - if (ground_foundreach) - { - //if area2 is higher but lower than the maximum step height - //NOTE: ground_bestdist >= 0 also catches equal floor reachabilities - if (ground_bestdist >= 0 && ground_bestdist < aassettings.phys_maxstep) - { - //create walk reachability from area1 to area2 - lreach = AAS_AllocReachability(); - if (!lreach) return qfalse; - lreach->areanum = area2num; - lreach->facenum = 0; - lreach->edgenum = ground_bestarea2groundedgenum; - VectorMA(ground_beststart, INSIDEUNITS_WALKSTART, ground_bestnormal, lreach->start); - VectorMA(ground_bestend, INSIDEUNITS_WALKEND, ground_bestnormal, lreach->end); - lreach->traveltype = TRAVEL_WALK; - lreach->traveltime = 0;//1; - //if going into a crouch area - if (!AAS_AreaCrouch(area1num) && AAS_AreaCrouch(area2num)) - { - lreach->traveltime += aassettings.rs_startcrouch; - } //end if - lreach->next = areareachability[area1num]; - areareachability[area1num] = lreach; - //NOTE: if there's nearby solid or a gap area after this area - /* - if (!AAS_NearbySolidOrGap(lreach->start, lreach->end)) - { - lreach->traveltime += 100; - } //end if - */ - //avoid rather small areas - //if (AAS_AreaGroundFaceArea(lreach->areanum) < 500) lreach->traveltime += 100; - // - reach_step++; - return qtrue; - } //end if - } //end if - // - // Water Jumps - // - // --------- - // | - //~~~~~~~~| - // | - // | higher than step height and water up to waterjump height -> TRAVEL_WATERJUMP - //--------| - // - //~~~~~~~~~~~~~~~~~~ - // --------- - // | - // | - // | - // | higher than step height and low water up to the step -> TRAVEL_WATERJUMP - //--------| - // - //check for a waterjump reachability - if (water_foundreach) - { - //get a test point a little bit towards area1 - VectorMA(water_bestend, -INSIDEUNITS, water_bestnormal, testpoint); - //go down the maximum waterjump height - testpoint[2] -= aassettings.phys_maxwaterjump; - //if there IS water the sv_maxwaterjump height below the bestend point - if (aasworld.areasettings[AAS_PointAreaNum(testpoint)].areaflags & AREA_LIQUID) - { - //don't create rediculous water jump reachabilities from areas very far below - //the water surface - if (water_bestdist < aassettings.phys_maxwaterjump + 24) - { - //waterjumping from or towards a crouch only area is not possible in Quake2 - if ((aasworld.areasettings[area1num].presencetype & PRESENCE_NORMAL) && - (aasworld.areasettings[area2num].presencetype & PRESENCE_NORMAL)) - { - //create water jump reachability from area1 to area2 - lreach = AAS_AllocReachability(); - if (!lreach) return qfalse; - lreach->areanum = area2num; - lreach->facenum = 0; - lreach->edgenum = water_bestarea2groundedgenum; - VectorCopy(water_beststart, lreach->start); - VectorMA(water_bestend, INSIDEUNITS_WATERJUMP, water_bestnormal, lreach->end); - lreach->traveltype = TRAVEL_WATERJUMP; - lreach->traveltime = aassettings.rs_waterjump; - lreach->next = areareachability[area1num]; - areareachability[area1num] = lreach; - //we've got another waterjump reachability - reach_waterjump++; - return qtrue; - } //end if - } //end if - } //end if - } //end if - // - // Barrier Jumps - // - // --------- - // | - // | - // | - // | higher than step height lower than barrier height -> TRAVEL_BARRIERJUMP - //--------| - // - // --------- - // | - // | - // | - //~~~~~~~~| higher than step height lower than barrier height - //--------| and a thin layer of water in the area to jump from -> TRAVEL_BARRIERJUMP - // - //check for a barrier jump reachability - if (ground_foundreach) - { - //if area2 is higher but lower than the maximum barrier jump height - if (ground_bestdist > 0 && ground_bestdist < aassettings.phys_maxbarrier) - { - //if no water in area1 or a very thin layer of water on the ground - if (!water_foundreach || (ground_bestdist - water_bestdist < 16)) - { - //cannot perform a barrier jump towards or from a crouch area in Quake2 - if (!AAS_AreaCrouch(area1num) && !AAS_AreaCrouch(area2num)) - { - //create barrier jump reachability from area1 to area2 - lreach = AAS_AllocReachability(); - if (!lreach) return qfalse; - lreach->areanum = area2num; - lreach->facenum = 0; - lreach->edgenum = ground_bestarea2groundedgenum; - VectorMA(ground_beststart, INSIDEUNITS_WALKSTART, ground_bestnormal, lreach->start); - VectorMA(ground_bestend, INSIDEUNITS_WALKEND, ground_bestnormal, lreach->end); - lreach->traveltype = TRAVEL_BARRIERJUMP; - lreach->traveltime = aassettings.rs_barrierjump;//AAS_BarrierJumpTravelTime(); - lreach->next = areareachability[area1num]; - areareachability[area1num] = lreach; - //we've got another barrierjump reachability - reach_barrier++; - return qtrue; - } //end if - } //end if - } //end if - } //end if - // - // Walk and Walk Off Ledge - // - //--------| - // | can walk or step back -> TRAVEL_WALK - // --------- - // - //--------| - // | - // | - // | - // | cannot walk/step back -> TRAVEL_WALKOFFLEDGE - // --------- - // - //--------| - // | - // |~~~~~~~~ - // | - // | cannot step back but can waterjump back -> TRAVEL_WALKOFFLEDGE - // --------- FIXME: create TRAVEL_WALK reach?? - // - //check for a walk or walk off ledge reachability - if (ground_foundreach) - { - if (ground_bestdist < 0) - { - if (ground_bestdist > -aassettings.phys_maxstep) - { - //create walk reachability from area1 to area2 - lreach = AAS_AllocReachability(); - if (!lreach) return qfalse; - lreach->areanum = area2num; - lreach->facenum = 0; - lreach->edgenum = ground_bestarea2groundedgenum; - VectorMA(ground_beststart, INSIDEUNITS_WALKSTART, ground_bestnormal, lreach->start); - VectorMA(ground_bestend, INSIDEUNITS_WALKEND, ground_bestnormal, lreach->end); - lreach->traveltype = TRAVEL_WALK; - lreach->traveltime = 1; - lreach->next = areareachability[area1num]; - areareachability[area1num] = lreach; - //we've got another walk reachability - reach_walk++; - return qtrue; - } //end if - // if no maximum fall height set or less than the max - if (!aassettings.rs_maxfallheight || fabs(ground_bestdist) < aassettings.rs_maxfallheight) { - //trace a bounding box vertically to check for solids - VectorMA(ground_bestend, INSIDEUNITS, ground_bestnormal, ground_bestend); - VectorCopy(ground_bestend, start); - start[2] = ground_beststart[2]; - VectorCopy(ground_bestend, end); - end[2] += 4; - trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, -1); - //if no solids were found - if (!trace.startsolid && trace.fraction >= 1.0) - { - //the trace end point must be in the goal area - trace.endpos[2] += 1; - if (AAS_PointAreaNum(trace.endpos) == area2num) - { - //if not going through a cluster portal - numareas = AAS_TraceAreas(start, end, areas, NULL, sizeof(areas) / sizeof(int)); - for (i = 0; i < numareas; i++) - if (AAS_AreaClusterPortal(areas[i])) - break; - if (i >= numareas) - { - //create a walk off ledge reachability from area1 to area2 - lreach = AAS_AllocReachability(); - if (!lreach) return qfalse; - lreach->areanum = area2num; - lreach->facenum = 0; - lreach->edgenum = ground_bestarea2groundedgenum; - VectorCopy(ground_beststart, lreach->start); - VectorCopy(ground_bestend, lreach->end); - lreach->traveltype = TRAVEL_WALKOFFLEDGE; - lreach->traveltime = aassettings.rs_startwalkoffledge + fabs(ground_bestdist) * 50 / aassettings.phys_gravity; - //if falling from too high and not falling into water - if (!AAS_AreaSwim(area2num) && !AAS_AreaJumpPad(area2num)) - { - if (AAS_FallDelta(ground_bestdist) > aassettings.phys_falldelta5) - { - lreach->traveltime += aassettings.rs_falldamage5; - } //end if - if (AAS_FallDelta(ground_bestdist) > aassettings.phys_falldelta10) - { - lreach->traveltime += aassettings.rs_falldamage10; - } //end if - } //end if - lreach->next = areareachability[area1num]; - areareachability[area1num] = lreach; - // - reach_walkoffledge++; - //NOTE: don't create a weapon (rl, bfg) jump reachability here - //because it interferes with other reachabilities - //like the ladder reachability - return qtrue; - } //end if - } //end if - } //end if - } //end if - } //end else - } //end if - return qfalse; -} //end of the function AAS_Reachability_Step_Barrier_WaterJump_WalkOffLedge -//=========================================================================== -// returns the distance between the two vectors -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -float VectorDistance(vec3_t v1, vec3_t v2) -{ - vec3_t dir; - - VectorSubtract(v2, v1, dir); - return VectorLength(dir); -} //end of the function VectorDistance -//=========================================================================== -// returns true if the first vector is between the last two vectors -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int VectorBetweenVectors(vec3_t v, vec3_t v1, vec3_t v2) -{ - vec3_t dir1, dir2; - - VectorSubtract(v, v1, dir1); - VectorSubtract(v, v2, dir2); - return (DotProduct(dir1, dir2) <= 0); -} //end of the function VectorBetweenVectors -//=========================================================================== -// returns the mid point between the two vectors -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void VectorMiddle(vec3_t v1, vec3_t v2, vec3_t middle) -{ - VectorAdd(v1, v2, middle); - VectorScale(middle, 0.5, middle); -} //end of the function VectorMiddle -//=========================================================================== -// calculate a range of points closest to each other on both edges -// -// Parameter: beststart1 start of the range of points on edge v1-v2 -// beststart2 end of the range of points on edge v1-v2 -// bestend1 start of the range of points on edge v3-v4 -// bestend2 end of the range of points on edge v3-v4 -// bestdist best distance so far -// Returns: - -// Changes Globals: - -//=========================================================================== -/* -float AAS_ClosestEdgePoints(vec3_t v1, vec3_t v2, vec3_t v3, vec3_t v4, - aas_plane_t *plane1, aas_plane_t *plane2, - vec3_t beststart, vec3_t bestend, float bestdist) -{ - vec3_t dir1, dir2, p1, p2, p3, p4; - float a1, a2, b1, b2, dist; - int founddist; - - //edge vectors - VectorSubtract(v2, v1, dir1); - VectorSubtract(v4, v3, dir2); - //get the horizontal directions - dir1[2] = 0; - dir2[2] = 0; - // - // p1 = point on an edge vector of area2 closest to v1 - // p2 = point on an edge vector of area2 closest to v2 - // p3 = point on an edge vector of area1 closest to v3 - // p4 = point on an edge vector of area1 closest to v4 - // - if (dir2[0]) - { - a2 = dir2[1] / dir2[0]; - b2 = v3[1] - a2 * v3[0]; - //point on the edge vector of area2 closest to v1 - p1[0] = (DotProduct(v1, dir2) - (a2 * dir2[0] + b2 * dir2[1])) / dir2[0]; - p1[1] = a2 * p1[0] + b2; - //point on the edge vector of area2 closest to v2 - p2[0] = (DotProduct(v2, dir2) - (a2 * dir2[0] + b2 * dir2[1])) / dir2[0]; - p2[1] = a2 * p2[0] + b2; - } //end if - else - { - //point on the edge vector of area2 closest to v1 - p1[0] = v3[0]; - p1[1] = v1[1]; - //point on the edge vector of area2 closest to v2 - p2[0] = v3[0]; - p2[1] = v2[1]; - } //end else - // - if (dir1[0]) - { - // - a1 = dir1[1] / dir1[0]; - b1 = v1[1] - a1 * v1[0]; - //point on the edge vector of area1 closest to v3 - p3[0] = (DotProduct(v3, dir1) - (a1 * dir1[0] + b1 * dir1[1])) / dir1[0]; - p3[1] = a1 * p3[0] + b1; - //point on the edge vector of area1 closest to v4 - p4[0] = (DotProduct(v4, dir1) - (a1 * dir1[0] + b1 * dir1[1])) / dir1[0]; - p4[1] = a1 * p4[0] + b1; - } //end if - else - { - //point on the edge vector of area1 closest to v3 - p3[0] = v1[0]; - p3[1] = v3[1]; - //point on the edge vector of area1 closest to v4 - p4[0] = v1[0]; - p4[1] = v4[1]; - } //end else - //start with zero z-coordinates - p1[2] = 0; - p2[2] = 0; - p3[2] = 0; - p4[2] = 0; - //calculate the z-coordinates from the ground planes - p1[2] = (plane2->dist - DotProduct(plane2->normal, p1)) / plane2->normal[2]; - p2[2] = (plane2->dist - DotProduct(plane2->normal, p2)) / plane2->normal[2]; - p3[2] = (plane1->dist - DotProduct(plane1->normal, p3)) / plane1->normal[2]; - p4[2] = (plane1->dist - DotProduct(plane1->normal, p4)) / plane1->normal[2]; - // - founddist = qfalse; - // - if (VectorBetweenVectors(p1, v3, v4)) - { - dist = VectorDistance(v1, p1); - if (dist > bestdist - 0.5 && dist < bestdist + 0.5) - { - VectorMiddle(beststart, v1, beststart); - VectorMiddle(bestend, p1, bestend); - } //end if - else if (dist < bestdist) - { - bestdist = dist; - VectorCopy(v1, beststart); - VectorCopy(p1, bestend); - } //end if - founddist = qtrue; - } //end if - if (VectorBetweenVectors(p2, v3, v4)) - { - dist = VectorDistance(v2, p2); - if (dist > bestdist - 0.5 && dist < bestdist + 0.5) - { - VectorMiddle(beststart, v2, beststart); - VectorMiddle(bestend, p2, bestend); - } //end if - else if (dist < bestdist) - { - bestdist = dist; - VectorCopy(v2, beststart); - VectorCopy(p2, bestend); - } //end if - founddist = qtrue; - } //end else if - if (VectorBetweenVectors(p3, v1, v2)) - { - dist = VectorDistance(v3, p3); - if (dist > bestdist - 0.5 && dist < bestdist + 0.5) - { - VectorMiddle(beststart, p3, beststart); - VectorMiddle(bestend, v3, bestend); - } //end if - else if (dist < bestdist) - { - bestdist = dist; - VectorCopy(p3, beststart); - VectorCopy(v3, bestend); - } //end if - founddist = qtrue; - } //end else if - if (VectorBetweenVectors(p4, v1, v2)) - { - dist = VectorDistance(v4, p4); - if (dist > bestdist - 0.5 && dist < bestdist + 0.5) - { - VectorMiddle(beststart, p4, beststart); - VectorMiddle(bestend, v4, bestend); - } //end if - else if (dist < bestdist) - { - bestdist = dist; - VectorCopy(p4, beststart); - VectorCopy(v4, bestend); - } //end if - founddist = qtrue; - } //end else if - //if no shortest distance was found the shortest distance - //is between one of the vertexes of edge1 and one of edge2 - if (!founddist) - { - dist = VectorDistance(v1, v3); - if (dist < bestdist) - { - bestdist = dist; - VectorCopy(v1, beststart); - VectorCopy(v3, bestend); - } //end if - dist = VectorDistance(v1, v4); - if (dist < bestdist) - { - bestdist = dist; - VectorCopy(v1, beststart); - VectorCopy(v4, bestend); - } //end if - dist = VectorDistance(v2, v3); - if (dist < bestdist) - { - bestdist = dist; - VectorCopy(v2, beststart); - VectorCopy(v3, bestend); - } //end if - dist = VectorDistance(v2, v4); - if (dist < bestdist) - { - bestdist = dist; - VectorCopy(v2, beststart); - VectorCopy(v4, bestend); - } //end if - } //end if - return bestdist; -} //end of the function AAS_ClosestEdgePoints*/ - -float AAS_ClosestEdgePoints(vec3_t v1, vec3_t v2, vec3_t v3, vec3_t v4, - aas_plane_t *plane1, aas_plane_t *plane2, - vec3_t beststart1, vec3_t bestend1, - vec3_t beststart2, vec3_t bestend2, float bestdist) -{ - vec3_t dir1, dir2, p1, p2, p3, p4; - float a1, a2, b1, b2, dist, dist1, dist2; - int founddist; - - //edge vectors - VectorSubtract(v2, v1, dir1); - VectorSubtract(v4, v3, dir2); - //get the horizontal directions - dir1[2] = 0; - dir2[2] = 0; - // - // p1 = point on an edge vector of area2 closest to v1 - // p2 = point on an edge vector of area2 closest to v2 - // p3 = point on an edge vector of area1 closest to v3 - // p4 = point on an edge vector of area1 closest to v4 - // - if (dir2[0]) - { - a2 = dir2[1] / dir2[0]; - b2 = v3[1] - a2 * v3[0]; - //point on the edge vector of area2 closest to v1 - p1[0] = (DotProduct(v1, dir2) - (a2 * dir2[0] + b2 * dir2[1])) / dir2[0]; - p1[1] = a2 * p1[0] + b2; - //point on the edge vector of area2 closest to v2 - p2[0] = (DotProduct(v2, dir2) - (a2 * dir2[0] + b2 * dir2[1])) / dir2[0]; - p2[1] = a2 * p2[0] + b2; - } //end if - else - { - //point on the edge vector of area2 closest to v1 - p1[0] = v3[0]; - p1[1] = v1[1]; - //point on the edge vector of area2 closest to v2 - p2[0] = v3[0]; - p2[1] = v2[1]; - } //end else - // - if (dir1[0]) - { - // - a1 = dir1[1] / dir1[0]; - b1 = v1[1] - a1 * v1[0]; - //point on the edge vector of area1 closest to v3 - p3[0] = (DotProduct(v3, dir1) - (a1 * dir1[0] + b1 * dir1[1])) / dir1[0]; - p3[1] = a1 * p3[0] + b1; - //point on the edge vector of area1 closest to v4 - p4[0] = (DotProduct(v4, dir1) - (a1 * dir1[0] + b1 * dir1[1])) / dir1[0]; - p4[1] = a1 * p4[0] + b1; - } //end if - else - { - //point on the edge vector of area1 closest to v3 - p3[0] = v1[0]; - p3[1] = v3[1]; - //point on the edge vector of area1 closest to v4 - p4[0] = v1[0]; - p4[1] = v4[1]; - } //end else - //start with zero z-coordinates - p1[2] = 0; - p2[2] = 0; - p3[2] = 0; - p4[2] = 0; - //calculate the z-coordinates from the ground planes - p1[2] = (plane2->dist - DotProduct(plane2->normal, p1)) / plane2->normal[2]; - p2[2] = (plane2->dist - DotProduct(plane2->normal, p2)) / plane2->normal[2]; - p3[2] = (plane1->dist - DotProduct(plane1->normal, p3)) / plane1->normal[2]; - p4[2] = (plane1->dist - DotProduct(plane1->normal, p4)) / plane1->normal[2]; - // - founddist = qfalse; - // - if (VectorBetweenVectors(p1, v3, v4)) - { - dist = VectorDistance(v1, p1); - if (dist > bestdist - 0.5 && dist < bestdist + 0.5) - { - dist1 = VectorDistance(beststart1, v1); - dist2 = VectorDistance(beststart2, v1); - if (dist1 > dist2) - { - if (dist1 > VectorDistance(beststart1, beststart2)) VectorCopy(v1, beststart2); - } //end if - else - { - if (dist2 > VectorDistance(beststart1, beststart2)) VectorCopy(v1, beststart1); - } //end else - dist1 = VectorDistance(bestend1, p1); - dist2 = VectorDistance(bestend2, p1); - if (dist1 > dist2) - { - if (dist1 > VectorDistance(bestend1, bestend2)) VectorCopy(p1, bestend2); - } //end if - else - { - if (dist2 > VectorDistance(bestend1, bestend2)) VectorCopy(p1, bestend1); - } //end else - } //end if - else if (dist < bestdist) - { - bestdist = dist; - VectorCopy(v1, beststart1); - VectorCopy(v1, beststart2); - VectorCopy(p1, bestend1); - VectorCopy(p1, bestend2); - } //end if - founddist = qtrue; - } //end if - if (VectorBetweenVectors(p2, v3, v4)) - { - dist = VectorDistance(v2, p2); - if (dist > bestdist - 0.5 && dist < bestdist + 0.5) - { - dist1 = VectorDistance(beststart1, v2); - dist2 = VectorDistance(beststart2, v2); - if (dist1 > dist2) - { - if (dist1 > VectorDistance(beststart1, beststart2)) VectorCopy(v2, beststart2); - } //end if - else - { - if (dist2 > VectorDistance(beststart1, beststart2)) VectorCopy(v2, beststart1); - } //end else - dist1 = VectorDistance(bestend1, p2); - dist2 = VectorDistance(bestend2, p2); - if (dist1 > dist2) - { - if (dist1 > VectorDistance(bestend1, bestend2)) VectorCopy(p2, bestend2); - } //end if - else - { - if (dist2 > VectorDistance(bestend1, bestend2)) VectorCopy(p2, bestend1); - } //end else - } //end if - else if (dist < bestdist) - { - bestdist = dist; - VectorCopy(v2, beststart1); - VectorCopy(v2, beststart2); - VectorCopy(p2, bestend1); - VectorCopy(p2, bestend2); - } //end if - founddist = qtrue; - } //end else if - if (VectorBetweenVectors(p3, v1, v2)) - { - dist = VectorDistance(v3, p3); - if (dist > bestdist - 0.5 && dist < bestdist + 0.5) - { - dist1 = VectorDistance(beststart1, p3); - dist2 = VectorDistance(beststart2, p3); - if (dist1 > dist2) - { - if (dist1 > VectorDistance(beststart1, beststart2)) VectorCopy(p3, beststart2); - } //end if - else - { - if (dist2 > VectorDistance(beststart1, beststart2)) VectorCopy(p3, beststart1); - } //end else - dist1 = VectorDistance(bestend1, v3); - dist2 = VectorDistance(bestend2, v3); - if (dist1 > dist2) - { - if (dist1 > VectorDistance(bestend1, bestend2)) VectorCopy(v3, bestend2); - } //end if - else - { - if (dist2 > VectorDistance(bestend1, bestend2)) VectorCopy(v3, bestend1); - } //end else - } //end if - else if (dist < bestdist) - { - bestdist = dist; - VectorCopy(p3, beststart1); - VectorCopy(p3, beststart2); - VectorCopy(v3, bestend1); - VectorCopy(v3, bestend2); - } //end if - founddist = qtrue; - } //end else if - if (VectorBetweenVectors(p4, v1, v2)) - { - dist = VectorDistance(v4, p4); - if (dist > bestdist - 0.5 && dist < bestdist + 0.5) - { - dist1 = VectorDistance(beststart1, p4); - dist2 = VectorDistance(beststart2, p4); - if (dist1 > dist2) - { - if (dist1 > VectorDistance(beststart1, beststart2)) VectorCopy(p4, beststart2); - } //end if - else - { - if (dist2 > VectorDistance(beststart1, beststart2)) VectorCopy(p4, beststart1); - } //end else - dist1 = VectorDistance(bestend1, v4); - dist2 = VectorDistance(bestend2, v4); - if (dist1 > dist2) - { - if (dist1 > VectorDistance(bestend1, bestend2)) VectorCopy(v4, bestend2); - } //end if - else - { - if (dist2 > VectorDistance(bestend1, bestend2)) VectorCopy(v4, bestend1); - } //end else - } //end if - else if (dist < bestdist) - { - bestdist = dist; - VectorCopy(p4, beststart1); - VectorCopy(p4, beststart2); - VectorCopy(v4, bestend1); - VectorCopy(v4, bestend2); - } //end if - founddist = qtrue; - } //end else if - //if no shortest distance was found the shortest distance - //is between one of the vertexes of edge1 and one of edge2 - if (!founddist) - { - dist = VectorDistance(v1, v3); - if (dist < bestdist) - { - bestdist = dist; - VectorCopy(v1, beststart1); - VectorCopy(v1, beststart2); - VectorCopy(v3, bestend1); - VectorCopy(v3, bestend2); - } //end if - dist = VectorDistance(v1, v4); - if (dist < bestdist) - { - bestdist = dist; - VectorCopy(v1, beststart1); - VectorCopy(v1, beststart2); - VectorCopy(v4, bestend1); - VectorCopy(v4, bestend2); - } //end if - dist = VectorDistance(v2, v3); - if (dist < bestdist) - { - bestdist = dist; - VectorCopy(v2, beststart1); - VectorCopy(v2, beststart2); - VectorCopy(v3, bestend1); - VectorCopy(v3, bestend2); - } //end if - dist = VectorDistance(v2, v4); - if (dist < bestdist) - { - bestdist = dist; - VectorCopy(v2, beststart1); - VectorCopy(v2, beststart2); - VectorCopy(v4, bestend1); - VectorCopy(v4, bestend2); - } //end if - } //end if - return bestdist; -} //end of the function AAS_ClosestEdgePoints -//=========================================================================== -// creates possible jump reachabilities between the areas -// -// The two closest points on the ground of the areas are calculated -// One of the points will be on an edge of a ground face of area1 and -// one on an edge of a ground face of area2. -// If there is a range of closest points the point in the middle of this range -// is selected. -// Between these two points there must be one or more gaps. -// If the gaps exist a potential jump is predicted. -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_Reachability_Jump(int area1num, int area2num) -{ - int i, j, k, l, face1num, face2num, edge1num, edge2num, traveltype; - int stopevent, areas[10], numareas; - float phys_jumpvel, maxjumpdistance, maxjumpheight, height, bestdist, speed; - vec_t *v1, *v2, *v3, *v4; - vec3_t beststart, beststart2, bestend, bestend2; - vec3_t teststart, testend, dir, velocity, cmdmove, up = {0, 0, 1}, sidewards; - aas_area_t *area1, *area2; - aas_face_t *face1, *face2; - aas_edge_t *edge1, *edge2; - aas_plane_t *plane1, *plane2, *plane; - aas_trace_t trace; - aas_clientmove_t move; - aas_lreachability_t *lreach; - - if (!AAS_AreaGrounded(area1num) || !AAS_AreaGrounded(area2num)) return qfalse; - //cannot jump from or to a crouch area - if (AAS_AreaCrouch(area1num) || AAS_AreaCrouch(area2num)) return qfalse; - // - area1 = &aasworld.areas[area1num]; - area2 = &aasworld.areas[area2num]; - // - phys_jumpvel = aassettings.phys_jumpvel; - //maximum distance a player can jump - maxjumpdistance = 2 * AAS_MaxJumpDistance(phys_jumpvel); - //maximum height a player can jump with the given initial z velocity - maxjumpheight = AAS_MaxJumpHeight(phys_jumpvel); - - //if the areas are not near anough in the x-y direction - for (i = 0; i < 2; i++) - { - if (area1->mins[i] > area2->maxs[i] + maxjumpdistance) return qfalse; - if (area1->maxs[i] < area2->mins[i] - maxjumpdistance) return qfalse; - } //end for - //if area2 is way to high to jump up to - if (area2->mins[2] > area1->maxs[2] + maxjumpheight) return qfalse; - // - bestdist = 999999; - // - for (i = 0; i < area1->numfaces; i++) - { - face1num = aasworld.faceindex[area1->firstface + i]; - face1 = &aasworld.faces[abs(face1num)]; - //if not a ground face - if (!(face1->faceflags & FACE_GROUND)) continue; - // - for (j = 0; j < area2->numfaces; j++) - { - face2num = aasworld.faceindex[area2->firstface + j]; - face2 = &aasworld.faces[abs(face2num)]; - //if not a ground face - if (!(face2->faceflags & FACE_GROUND)) continue; - // - for (k = 0; k < face1->numedges; k++) - { - edge1num = abs(aasworld.edgeindex[face1->firstedge + k]); - edge1 = &aasworld.edges[edge1num]; - for (l = 0; l < face2->numedges; l++) - { - edge2num = abs(aasworld.edgeindex[face2->firstedge + l]); - edge2 = &aasworld.edges[edge2num]; - //calculate the minimum distance between the two edges - v1 = aasworld.vertexes[edge1->v[0]]; - v2 = aasworld.vertexes[edge1->v[1]]; - v3 = aasworld.vertexes[edge2->v[0]]; - v4 = aasworld.vertexes[edge2->v[1]]; - //get the ground planes - plane1 = &aasworld.planes[face1->planenum]; - plane2 = &aasworld.planes[face2->planenum]; - // - bestdist = AAS_ClosestEdgePoints(v1, v2, v3, v4, plane1, plane2, - beststart, bestend, - beststart2, bestend2, bestdist); - } //end for - } //end for - } //end for - } //end for - VectorMiddle(beststart, beststart2, beststart); - VectorMiddle(bestend, bestend2, bestend); - if (bestdist > 4 && bestdist < maxjumpdistance) - { -// Log_Write("shortest distance between %d and %d is %f\r\n", area1num, area2num, bestdist); - // if very close and almost no height difference then the bot can walk - if (bestdist <= 48 && fabs(beststart[2] - bestend[2]) < 8) - { - speed = 400; - traveltype = TRAVEL_WALKOFFLEDGE; - } //end if - else if (AAS_HorizontalVelocityForJump(0, beststart, bestend, &speed)) - { - //FIXME: why multiply with 1.2??? - speed *= 1.2f; - traveltype = TRAVEL_WALKOFFLEDGE; - } //end else if - else - { - //get the horizontal speed for the jump, if it isn't possible to calculate this - //speed (the jump is not possible) then there's no jump reachability created - if (!AAS_HorizontalVelocityForJump(phys_jumpvel, beststart, bestend, &speed)) - return qfalse; - speed *= 1.05f; - traveltype = TRAVEL_JUMP; - // - //NOTE: test if the horizontal distance isn't too small - VectorSubtract(bestend, beststart, dir); - dir[2] = 0; - if (VectorLength(dir) < 10) - return qfalse; - } //end if - // - VectorSubtract(bestend, beststart, dir); - VectorNormalize(dir); - VectorMA(beststart, 1, dir, teststart); - // - VectorCopy(teststart, testend); - testend[2] -= 100; - trace = AAS_TraceClientBBox(teststart, testend, PRESENCE_NORMAL, -1); - // - if (trace.startsolid) - return qfalse; - if (trace.fraction < 1) - { - plane = &aasworld.planes[trace.planenum]; - // if the bot can stand on the surface - if (DotProduct(plane->normal, up) >= 0.7) - { - // if no lava or slime below - if (!(AAS_PointContents(trace.endpos) & (CONTENTS_LAVA|CONTENTS_SLIME))) - { - if (teststart[2] - trace.endpos[2] <= aassettings.phys_maxbarrier) - return qfalse; - } //end if - } //end if - } //end if - // - VectorMA(bestend, -1, dir, teststart); - // - VectorCopy(teststart, testend); - testend[2] -= 100; - trace = AAS_TraceClientBBox(teststart, testend, PRESENCE_NORMAL, -1); - // - if (trace.startsolid) - return qfalse; - if (trace.fraction < 1) - { - plane = &aasworld.planes[trace.planenum]; - // if the bot can stand on the surface - if (DotProduct(plane->normal, up) >= 0.7) - { - // if no lava or slime below - if (!(AAS_PointContents(trace.endpos) & (CONTENTS_LAVA|CONTENTS_SLIME))) - { - if (teststart[2] - trace.endpos[2] <= aassettings.phys_maxbarrier) - return qfalse; - } //end if - } //end if - } //end if - // - // get command movement - VectorClear(cmdmove); - if ((traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMP) - cmdmove[2] = aassettings.phys_jumpvel; - else - cmdmove[2] = 0; - // - VectorSubtract(bestend, beststart, dir); - dir[2] = 0; - VectorNormalize(dir); - CrossProduct(dir, up, sidewards); - // - stopevent = SE_HITGROUND|SE_ENTERWATER|SE_ENTERSLIME|SE_ENTERLAVA|SE_HITGROUNDDAMAGE; - if (!AAS_AreaClusterPortal(area1num) && !AAS_AreaClusterPortal(area2num)) - stopevent |= SE_TOUCHCLUSTERPORTAL; - // - for (i = 0; i < 3; i++) - { - // - if (i == 1) - VectorAdd(testend, sidewards, testend); - else if (i == 2) - VectorSubtract(bestend, sidewards, testend); - else - VectorCopy(bestend, testend); - VectorSubtract(testend, beststart, dir); - dir[2] = 0; - VectorNormalize(dir); - VectorScale(dir, speed, velocity); - // - AAS_PredictClientMovement(&move, -1, beststart, PRESENCE_NORMAL, qtrue, - velocity, cmdmove, 3, 30, 0.1f, - stopevent, 0, qfalse); - // if prediction time wasn't enough to fully predict the movement - if (move.frames >= 30) - return qfalse; - // don't enter slime or lava and don't fall from too high - if (move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA)) - return qfalse; - // never jump or fall through a cluster portal - if (move.stopevent & SE_TOUCHCLUSTERPORTAL) - return qfalse; - //the end position should be in area2, also test a little bit back - //because the predicted jump could have rushed through the area - VectorMA(move.endpos, -64, dir, teststart); - teststart[2] += 1; - numareas = AAS_TraceAreas(move.endpos, teststart, areas, NULL, sizeof(areas) / sizeof(int)); - for (j = 0; j < numareas; j++) - { - if (areas[j] == area2num) - break; - } //end for - if (j < numareas) - break; - } - if (i >= 3) - return qfalse; - // -#ifdef REACH_DEBUG - //create the reachability - Log_Write("jump reachability between %d and %d\r\n", area1num, area2num); -#endif //REACH_DEBUG - //create a new reachability link - lreach = AAS_AllocReachability(); - if (!lreach) return qfalse; - lreach->areanum = area2num; - lreach->facenum = 0; - lreach->edgenum = 0; - VectorCopy(beststart, lreach->start); - VectorCopy(bestend, lreach->end); - lreach->traveltype = traveltype; - - VectorSubtract(bestend, beststart, dir); - height = dir[2]; - dir[2] = 0; - if ((traveltype & TRAVELTYPE_MASK) == TRAVEL_WALKOFFLEDGE && height > VectorLength(dir)) - { - lreach->traveltime = aassettings.rs_startwalkoffledge + height * 50 / aassettings.phys_gravity; - } - else - { - lreach->traveltime = aassettings.rs_startjump + VectorDistance(bestend, beststart) * 240 / aassettings.phys_maxwalkvelocity; - } //end if - // - if (!AAS_AreaJumpPad(area2num)) - { - if (AAS_FallDelta(beststart[2] - bestend[2]) > aassettings.phys_falldelta5) - { - lreach->traveltime += aassettings.rs_falldamage5; - } //end if - else if (AAS_FallDelta(beststart[2] - bestend[2]) > aassettings.phys_falldelta10) - { - lreach->traveltime += aassettings.rs_falldamage10; - } //end if - } //end if - lreach->next = areareachability[area1num]; - areareachability[area1num] = lreach; - // - if ((traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMP) - reach_jump++; - else - reach_walkoffledge++; - } //end if - return qfalse; -} //end of the function AAS_Reachability_Jump -//=========================================================================== -// create a possible ladder reachability from area1 to area2 -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_Reachability_Ladder(int area1num, int area2num) -{ - int i, j, k, l, edge1num, edge2num, sharededgenum = 0, lowestedgenum = 0; - int face1num, face2num, ladderface1num = 0, ladderface2num = 0; - int ladderface1vertical, ladderface2vertical, firstv; - float face1area, face2area, bestface1area = -9999, bestface2area = -9999; - float phys_jumpvel, maxjumpheight; - vec3_t area1point, area2point, v1, v2, up = {0, 0, 1}; - vec3_t mid, lowestpoint = {0, 0}, start, end, sharededgevec, dir; - aas_area_t *area1, *area2; - aas_face_t *face1, *face2, *ladderface1 = NULL, *ladderface2 = NULL; - aas_plane_t *plane1, *plane2; - aas_edge_t *sharededge, *edge1; - aas_lreachability_t *lreach; - aas_trace_t trace; - - if (!AAS_AreaLadder(area1num) || !AAS_AreaLadder(area2num)) return qfalse; - // - phys_jumpvel = aassettings.phys_jumpvel; - //maximum height a player can jump with the given initial z velocity - maxjumpheight = AAS_MaxJumpHeight(phys_jumpvel); - - area1 = &aasworld.areas[area1num]; - area2 = &aasworld.areas[area2num]; - - for (i = 0; i < area1->numfaces; i++) - { - face1num = aasworld.faceindex[area1->firstface + i]; - face1 = &aasworld.faces[abs(face1num)]; - //if not a ladder face - if (!(face1->faceflags & FACE_LADDER)) continue; - // - for (j = 0; j < area2->numfaces; j++) - { - face2num = aasworld.faceindex[area2->firstface + j]; - face2 = &aasworld.faces[abs(face2num)]; - //if not a ladder face - if (!(face2->faceflags & FACE_LADDER)) continue; - //check if the faces share an edge - for (k = 0; k < face1->numedges; k++) - { - edge1num = aasworld.edgeindex[face1->firstedge + k]; - for (l = 0; l < face2->numedges; l++) - { - edge2num = aasworld.edgeindex[face2->firstedge + l]; - if (abs(edge1num) == abs(edge2num)) - { - //get the face with the largest area - face1area = AAS_FaceArea(face1); - face2area = AAS_FaceArea(face2); - if (face1area > bestface1area && face2area > bestface2area) - { - bestface1area = face1area; - bestface2area = face2area; - ladderface1 = face1; - ladderface2 = face2; - ladderface1num = face1num; - ladderface2num = face2num; - sharededgenum = edge1num; - } //end if - break; - } //end if - } //end for - if (l != face2->numedges) break; - } //end for - } //end for - } //end for - // - if (ladderface1 && ladderface2) - { - //get the middle of the shared edge - sharededge = &aasworld.edges[abs(sharededgenum)]; - firstv = sharededgenum < 0; - // - VectorCopy(aasworld.vertexes[sharededge->v[firstv]], v1); - VectorCopy(aasworld.vertexes[sharededge->v[!firstv]], v2); - VectorAdd(v1, v2, area1point); - VectorScale(area1point, 0.5, area1point); - VectorCopy(area1point, area2point); - // - //if the face plane in area 1 is pretty much vertical - plane1 = &aasworld.planes[ladderface1->planenum ^ (ladderface1num < 0)]; - plane2 = &aasworld.planes[ladderface2->planenum ^ (ladderface2num < 0)]; - // - //get the points really into the areas - VectorSubtract(v2, v1, sharededgevec); - CrossProduct(plane1->normal, sharededgevec, dir); - VectorNormalize(dir); - //NOTE: 32 because that's larger than 16 (bot bbox x,y) - VectorMA(area1point, -32, dir, area1point); - VectorMA(area2point, 32, dir, area2point); - // - ladderface1vertical = abs(DotProduct(plane1->normal, up)) < 0.1; - ladderface2vertical = abs(DotProduct(plane2->normal, up)) < 0.1; - //there's only reachability between vertical ladder faces - if (!ladderface1vertical && !ladderface2vertical) return qfalse; - //if both vertical ladder faces - if (ladderface1vertical && ladderface2vertical - //and the ladder faces do not make a sharp corner - && DotProduct(plane1->normal, plane2->normal) > 0.7 - //and the shared edge is not too vertical - && abs(DotProduct(sharededgevec, up)) < 0.7) - { - //create a new reachability link - lreach = AAS_AllocReachability(); - if (!lreach) return qfalse; - lreach->areanum = area2num; - lreach->facenum = ladderface1num; - lreach->edgenum = abs(sharededgenum); - VectorCopy(area1point, lreach->start); - //VectorCopy(area2point, lreach->end); - VectorMA(area2point, -3, plane1->normal, lreach->end); - lreach->traveltype = TRAVEL_LADDER; - lreach->traveltime = 10; - lreach->next = areareachability[area1num]; - areareachability[area1num] = lreach; - // - reach_ladder++; - //create a new reachability link - lreach = AAS_AllocReachability(); - if (!lreach) return qfalse; - lreach->areanum = area1num; - lreach->facenum = ladderface2num; - lreach->edgenum = abs(sharededgenum); - VectorCopy(area2point, lreach->start); - //VectorCopy(area1point, lreach->end); - VectorMA(area1point, -3, plane1->normal, lreach->end); - lreach->traveltype = TRAVEL_LADDER; - lreach->traveltime = 10; - lreach->next = areareachability[area2num]; - areareachability[area2num] = lreach; - // - reach_ladder++; - // - return qtrue; - } //end if - //if the second ladder face is also a ground face - //create ladder end (just ladder) reachability and - //walk off a ladder (ledge) reachability - if (ladderface1vertical && (ladderface2->faceflags & FACE_GROUND)) - { - //create a new reachability link - lreach = AAS_AllocReachability(); - if (!lreach) return qfalse; - lreach->areanum = area2num; - lreach->facenum = ladderface1num; - lreach->edgenum = abs(sharededgenum); - VectorCopy(area1point, lreach->start); - VectorCopy(area2point, lreach->end); - lreach->end[2] += 16; - VectorMA(lreach->end, -15, plane1->normal, lreach->end); - lreach->traveltype = TRAVEL_LADDER; - lreach->traveltime = 10; - lreach->next = areareachability[area1num]; - areareachability[area1num] = lreach; - // - reach_ladder++; - //create a new reachability link - lreach = AAS_AllocReachability(); - if (!lreach) return qfalse; - lreach->areanum = area1num; - lreach->facenum = ladderface2num; - lreach->edgenum = abs(sharededgenum); - VectorCopy(area2point, lreach->start); - VectorCopy(area1point, lreach->end); - lreach->traveltype = TRAVEL_WALKOFFLEDGE; - lreach->traveltime = 10; - lreach->next = areareachability[area2num]; - areareachability[area2num] = lreach; - // - reach_walkoffledge++; - // - return qtrue; - } //end if - // - if (ladderface1vertical) - { - //find lowest edge of the ladder face - lowestpoint[2] = 99999; - for (i = 0; i < ladderface1->numedges; i++) - { - edge1num = abs(aasworld.edgeindex[ladderface1->firstedge + i]); - edge1 = &aasworld.edges[edge1num]; - // - VectorCopy(aasworld.vertexes[edge1->v[0]], v1); - VectorCopy(aasworld.vertexes[edge1->v[1]], v2); - // - VectorAdd(v1, v2, mid); - VectorScale(mid, 0.5, mid); - // - if (mid[2] < lowestpoint[2]) - { - VectorCopy(mid, lowestpoint); - lowestedgenum = edge1num; - } //end if - } //end for - // - plane1 = &aasworld.planes[ladderface1->planenum]; - //trace down in the middle of this edge - VectorMA(lowestpoint, 5, plane1->normal, start); - VectorCopy(start, end); - start[2] += 5; - end[2] -= 100; - //trace without entity collision - trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, -1); - // - // -#ifdef REACH_DEBUG - if (trace.startsolid) - { - Log_Write("trace from area %d started in solid\r\n", area1num); - } //end if -#endif //REACH_DEBUG - // - trace.endpos[2] += 1; - area2num = AAS_PointAreaNum(trace.endpos); - // - area2 = &aasworld.areas[area2num]; - for (i = 0; i < area2->numfaces; i++) - { - face2num = aasworld.faceindex[area2->firstface + i]; - face2 = &aasworld.faces[abs(face2num)]; - // - if (face2->faceflags & FACE_LADDER) - { - plane2 = &aasworld.planes[face2->planenum]; - if (abs(DotProduct(plane2->normal, up)) < 0.1) break; - } //end if - } //end for - //if from another area without vertical ladder faces - if (i >= area2->numfaces && area2num != area1num && - //the reachabilities shouldn't exist already - !AAS_ReachabilityExists(area1num, area2num) && - !AAS_ReachabilityExists(area2num, area1num)) - { - //if the height is jumpable - if (start[2] - trace.endpos[2] < maxjumpheight) - { - //create a new reachability link - lreach = AAS_AllocReachability(); - if (!lreach) return qfalse; - lreach->areanum = area2num; - lreach->facenum = ladderface1num; - lreach->edgenum = lowestedgenum; - VectorCopy(lowestpoint, lreach->start); - VectorCopy(trace.endpos, lreach->end); - lreach->traveltype = TRAVEL_LADDER; - lreach->traveltime = 10; - lreach->next = areareachability[area1num]; - areareachability[area1num] = lreach; - // - reach_ladder++; - //create a new reachability link - lreach = AAS_AllocReachability(); - if (!lreach) return qfalse; - lreach->areanum = area1num; - lreach->facenum = ladderface1num; - lreach->edgenum = lowestedgenum; - VectorCopy(trace.endpos, lreach->start); - //get the end point a little bit into the ladder - VectorMA(lowestpoint, -5, plane1->normal, lreach->end); - //get the end point a little higher - lreach->end[2] += 10; - lreach->traveltype = TRAVEL_JUMP; - lreach->traveltime = 10; - lreach->next = areareachability[area2num]; - areareachability[area2num] = lreach; - // - reach_jump++; - // - return qtrue; -#ifdef REACH_DEBUG - Log_Write("jump up to ladder reach between %d and %d\r\n", area2num, area1num); -#endif //REACH_DEBUG - } //end if -#ifdef REACH_DEBUG - else Log_Write("jump too high between area %d and %d\r\n", area2num, area1num); -#endif //REACH_DEBUG - } //end if - /*//if slime or lava below the ladder - //try jump reachability from far towards the ladder - if (aasworld.areasettings[area2num].contents & (AREACONTENTS_SLIME - | AREACONTENTS_LAVA)) - { - for (i = 20; i <= 120; i += 20) - { - //trace down in the middle of this edge - VectorMA(lowestpoint, i, plane1->normal, start); - VectorCopy(start, end); - start[2] += 5; - end[2] -= 100; - //trace without entity collision - trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, -1); - // - if (trace.startsolid) break; - trace.endpos[2] += 1; - area2num = AAS_PointAreaNum(trace.endpos); - if (area2num == area1num) continue; - // - if (start[2] - trace.endpos[2] > maxjumpheight) continue; - if (aasworld.areasettings[area2num].contents & (AREACONTENTS_SLIME - | AREACONTENTS_LAVA)) continue; - // - //create a new reachability link - lreach = AAS_AllocReachability(); - if (!lreach) return qfalse; - lreach->areanum = area1num; - lreach->facenum = ladderface1num; - lreach->edgenum = lowestedgenum; - VectorCopy(trace.endpos, lreach->start); - VectorCopy(lowestpoint, lreach->end); - lreach->end[2] += 5; - lreach->traveltype = TRAVEL_JUMP; - lreach->traveltime = 10; - lreach->next = areareachability[area2num]; - areareachability[area2num] = lreach; - // - reach_jump++; - // - Log_Write("jump far to ladder reach between %d and %d\r\n", area2num, area1num); - // - break; - } //end for - } //end if*/ - } //end if - } //end if - return qfalse; -} //end of the function AAS_Reachability_Ladder -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_TravelFlagsForTeam(int ent) -{ - int notteam; - - if (!AAS_IntForBSPEpairKey(ent, "bot_notteam", ¬team)) - return 0; - if (notteam == 1) - return TRAVELFLAG_NOTTEAM1; - if (notteam == 2) - return TRAVELFLAG_NOTTEAM2; - return 0; -} //end of the function AAS_TravelFlagsForTeam -//=========================================================================== -// create possible teleporter reachabilities -// this is very game dependent.... :( -// -// classname = trigger_multiple or trigger_teleport -// target = "t1" -// -// classname = target_teleporter -// targetname = "t1" -// target = "t2" -// -// classname = misc_teleporter_dest -// targetname = "t2" -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_Reachability_Teleport(void) -{ - int area1num, area2num; - char target[MAX_EPAIRKEY], targetname[MAX_EPAIRKEY]; - char classname[MAX_EPAIRKEY], model[MAX_EPAIRKEY]; - int ent, dest; - float angle; - vec3_t origin, destorigin, mins, maxs, end, angles; - vec3_t mid, velocity, cmdmove; - aas_lreachability_t *lreach; - aas_clientmove_t move; - aas_trace_t trace; - aas_link_t *areas, *link; - - for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent)) - { - if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue; - if (!strcmp(classname, "trigger_multiple")) - { - AAS_ValueForBSPEpairKey(ent, "model", model, MAX_EPAIRKEY); -//#ifdef REACH_DEBUG - botimport.Print(PRT_MESSAGE, "trigger_multiple model = \"%s\"\n", model); -//#endif REACH_DEBUG - VectorClear(angles); - AAS_BSPModelMinsMaxsOrigin(atoi(model+1), angles, mins, maxs, origin); - // - if (!AAS_ValueForBSPEpairKey(ent, "target", target, MAX_EPAIRKEY)) - { - botimport.Print(PRT_ERROR, "trigger_multiple at %1.0f %1.0f %1.0f without target\n", - origin[0], origin[1], origin[2]); - continue; - } //end if - for (dest = AAS_NextBSPEntity(0); dest; dest = AAS_NextBSPEntity(dest)) - { - if (!AAS_ValueForBSPEpairKey(dest, "classname", classname, MAX_EPAIRKEY)) continue; - if (!strcmp(classname, "target_teleporter")) - { - if (!AAS_ValueForBSPEpairKey(dest, "targetname", targetname, MAX_EPAIRKEY)) continue; - if (!strcmp(targetname, target)) - { - break; - } //end if - } //end if - } //end for - if (!dest) - { - continue; - } //end if - if (!AAS_ValueForBSPEpairKey(dest, "target", target, MAX_EPAIRKEY)) - { - botimport.Print(PRT_ERROR, "target_teleporter without target\n"); - continue; - } //end if - } //end else - else if (!strcmp(classname, "trigger_teleport")) - { - AAS_ValueForBSPEpairKey(ent, "model", model, MAX_EPAIRKEY); -//#ifdef REACH_DEBUG - botimport.Print(PRT_MESSAGE, "trigger_teleport model = \"%s\"\n", model); -//#endif REACH_DEBUG - VectorClear(angles); - AAS_BSPModelMinsMaxsOrigin(atoi(model+1), angles, mins, maxs, origin); - // - if (!AAS_ValueForBSPEpairKey(ent, "target", target, MAX_EPAIRKEY)) - { - botimport.Print(PRT_ERROR, "trigger_teleport at %1.0f %1.0f %1.0f without target\n", - origin[0], origin[1], origin[2]); - continue; - } //end if - } //end if - else - { - continue; - } //end else - // - for (dest = AAS_NextBSPEntity(0); dest; dest = AAS_NextBSPEntity(dest)) - { - //classname should be misc_teleporter_dest - //but I've also seen target_position and actually any - //entity could be used... burp - if (AAS_ValueForBSPEpairKey(dest, "targetname", targetname, MAX_EPAIRKEY)) - { - if (!strcmp(targetname, target)) - { - break; - } //end if - } //end if - } //end for - if (!dest) - { - botimport.Print(PRT_ERROR, "teleporter without misc_teleporter_dest (%s)\n", target); - continue; - } //end if - if (!AAS_VectorForBSPEpairKey(dest, "origin", destorigin)) - { - botimport.Print(PRT_ERROR, "teleporter destination (%s) without origin\n", target); - continue; - } //end if - // - area2num = AAS_PointAreaNum(destorigin); - //if not teleported into a teleporter or into a jumppad - if (!AAS_AreaTeleporter(area2num) && !AAS_AreaJumpPad(area2num)) - { - VectorCopy(destorigin, end); - end[2] -= 64; - trace = AAS_TraceClientBBox(destorigin, end, PRESENCE_CROUCH, -1); - if (trace.startsolid) - { - botimport.Print(PRT_ERROR, "teleporter destination (%s) in solid\n", target); - continue; - } //end if - area2num = AAS_PointAreaNum(trace.endpos); - // - /* - if (!AAS_AreaTeleporter(area2num) && - !AAS_AreaJumpPad(area2num) && - !AAS_AreaGrounded(area2num)) - { - VectorCopy(trace.endpos, destorigin); - } - else*/ - { - //predict where you'll end up - AAS_FloatForBSPEpairKey(dest, "angle", &angle); - if (angle) - { - VectorSet(angles, 0, angle, 0); - AngleVectors(angles, velocity, NULL, NULL); - VectorScale(velocity, 400, velocity); - } //end if - else - { - VectorClear(velocity); - } //end else - VectorClear(cmdmove); - AAS_PredictClientMovement(&move, -1, destorigin, PRESENCE_NORMAL, qfalse, - velocity, cmdmove, 0, 30, 0.1f, - SE_HITGROUND|SE_ENTERWATER|SE_ENTERSLIME| - SE_ENTERLAVA|SE_HITGROUNDDAMAGE|SE_TOUCHJUMPPAD|SE_TOUCHTELEPORTER, 0, qfalse); //qtrue); - area2num = AAS_PointAreaNum(move.endpos); - if (move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA)) - { - botimport.Print(PRT_WARNING, "teleported into slime or lava at dest %s\n", target); - } //end if - VectorCopy(move.endpos, destorigin); - } //end else - } //end if - // - //botimport.Print(PRT_MESSAGE, "teleporter brush origin at %f %f %f\n", origin[0], origin[1], origin[2]); - //botimport.Print(PRT_MESSAGE, "teleporter brush mins = %f %f %f\n", mins[0], mins[1], mins[2]); - //botimport.Print(PRT_MESSAGE, "teleporter brush maxs = %f %f %f\n", maxs[0], maxs[1], maxs[2]); - VectorAdd(origin, mins, mins); - VectorAdd(origin, maxs, maxs); - // - VectorAdd(mins, maxs, mid); - VectorScale(mid, 0.5, mid); - //link an invalid (-1) entity - areas = AAS_LinkEntityClientBBox(mins, maxs, -1, PRESENCE_CROUCH); - if (!areas) botimport.Print(PRT_MESSAGE, "trigger_multiple not in any area\n"); - // - for (link = areas; link; link = link->next_area) - { - //if (!AAS_AreaGrounded(link->areanum)) continue; - if (!AAS_AreaTeleporter(link->areanum)) continue; - // - area1num = link->areanum; - //create a new reachability link - lreach = AAS_AllocReachability(); - if (!lreach) break; - lreach->areanum = area2num; - lreach->facenum = 0; - lreach->edgenum = 0; - VectorCopy(mid, lreach->start); - VectorCopy(destorigin, lreach->end); - lreach->traveltype = TRAVEL_TELEPORT; - lreach->traveltype |= AAS_TravelFlagsForTeam(ent); - lreach->traveltime = aassettings.rs_teleport; - lreach->next = areareachability[area1num]; - areareachability[area1num] = lreach; - // - reach_teleport++; - } //end for - //unlink the invalid entity - AAS_UnlinkFromAreas(areas); - } //end for -} //end of the function AAS_Reachability_Teleport -//=========================================================================== -// create possible elevator (func_plat) reachabilities -// this is very game dependent.... :( -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_Reachability_Elevator(void) -{ - int area1num, area2num, modelnum, i, j, k, l, n, p; - float lip, height, speed; - char model[MAX_EPAIRKEY], classname[MAX_EPAIRKEY]; - int ent; - vec3_t mins, maxs, origin, angles = {0, 0, 0}; - vec3_t pos1, pos2, mids, platbottom, plattop; - vec3_t bottomorg, toporg, start, end, dir; - vec_t xvals[8], yvals[8], xvals_top[8], yvals_top[8]; - aas_lreachability_t *lreach; - aas_trace_t trace; - -#ifdef REACH_DEBUG - Log_Write("AAS_Reachability_Elevator\r\n"); -#endif //REACH_DEBUG - for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent)) - { - if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue; - if (!strcmp(classname, "func_plat")) - { -#ifdef REACH_DEBUG - Log_Write("found func plat\r\n"); -#endif //REACH_DEBUG - if (!AAS_ValueForBSPEpairKey(ent, "model", model, MAX_EPAIRKEY)) - { - botimport.Print(PRT_ERROR, "func_plat without model\n"); - continue; - } //end if - //get the model number, and skip the leading * - modelnum = atoi(model+1); - if (modelnum <= 0) - { - botimport.Print(PRT_ERROR, "func_plat with invalid model number\n"); - continue; - } //end if - //get the mins, maxs and origin of the model - //NOTE: the origin is usually (0,0,0) and the mins and maxs - // are the absolute mins and maxs - AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, origin); - // - AAS_VectorForBSPEpairKey(ent, "origin", origin); - //pos1 is the top position, pos2 is the bottom - VectorCopy(origin, pos1); - VectorCopy(origin, pos2); - //get the lip of the plat - AAS_FloatForBSPEpairKey(ent, "lip", &lip); - if (!lip) lip = 8; - //get the movement height of the plat - AAS_FloatForBSPEpairKey(ent, "height", &height); - if (!height) height = (maxs[2] - mins[2]) - lip; - //get the speed of the plat - AAS_FloatForBSPEpairKey(ent, "speed", &speed); - if (!speed) speed = 200; - //get bottom position below pos1 - pos2[2] -= height; - // - //get a point just above the plat in the bottom position - VectorAdd(mins, maxs, mids); - VectorMA(pos2, 0.5, mids, platbottom); - platbottom[2] = maxs[2] - (pos1[2] - pos2[2]) + 2; - //get a point just above the plat in the top position - VectorAdd(mins, maxs, mids); - VectorMA(pos2, 0.5, mids, plattop); - plattop[2] = maxs[2] + 2; - // - /*if (!area1num) - { - Log_Write("no grounded area near plat bottom\r\n"); - continue; - } //end if*/ - //get the mins and maxs a little larger - for (i = 0; i < 3; i++) - { - mins[i] -= 1; - maxs[i] += 1; - } //end for - // - //botimport.Print(PRT_MESSAGE, "platbottom[2] = %1.1f plattop[2] = %1.1f\n", platbottom[2], plattop[2]); - // - VectorAdd(mins, maxs, mids); - VectorScale(mids, 0.5, mids); - // - xvals[0] = mins[0]; xvals[1] = mids[0]; xvals[2] = maxs[0]; xvals[3] = mids[0]; - yvals[0] = mids[1]; yvals[1] = maxs[1]; yvals[2] = mids[1]; yvals[3] = mins[1]; - // - xvals[4] = mins[0]; xvals[5] = maxs[0]; xvals[6] = maxs[0]; xvals[7] = mins[0]; - yvals[4] = maxs[1]; yvals[5] = maxs[1]; yvals[6] = mins[1]; yvals[7] = mins[1]; - //find adjacent areas around the bottom of the plat - for (i = 0; i < 9; i++) - { - if (i < 8) //check at the sides of the plat - { - bottomorg[0] = origin[0] + xvals[i]; - bottomorg[1] = origin[1] + yvals[i]; - bottomorg[2] = platbottom[2] + 16; - //get a grounded or swim area near the plat in the bottom position - area1num = AAS_PointAreaNum(bottomorg); - for (k = 0; k < 16; k++) - { - if (area1num) - { - if (AAS_AreaGrounded(area1num) || AAS_AreaSwim(area1num)) break; - } //end if - bottomorg[2] += 4; - area1num = AAS_PointAreaNum(bottomorg); - } //end if - //if in solid - if (k >= 16) - { - continue; - } //end if - } //end if - else //at the middle of the plat - { - VectorCopy(plattop, bottomorg); - bottomorg[2] += 24; - area1num = AAS_PointAreaNum(bottomorg); - if (!area1num) continue; - VectorCopy(platbottom, bottomorg); - bottomorg[2] += 24; - } //end else - //look at adjacent areas around the top of the plat - //make larger steps to outside the plat everytime - for (n = 0; n < 3; n++) - { - for (k = 0; k < 3; k++) - { - mins[k] -= 4; - maxs[k] += 4; - } //end for - xvals_top[0] = mins[0]; xvals_top[1] = mids[0]; xvals_top[2] = maxs[0]; xvals_top[3] = mids[0]; - yvals_top[0] = mids[1]; yvals_top[1] = maxs[1]; yvals_top[2] = mids[1]; yvals_top[3] = mins[1]; - // - xvals_top[4] = mins[0]; xvals_top[5] = maxs[0]; xvals_top[6] = maxs[0]; xvals_top[7] = mins[0]; - yvals_top[4] = maxs[1]; yvals_top[5] = maxs[1]; yvals_top[6] = mins[1]; yvals_top[7] = mins[1]; - // - for (j = 0; j < 8; j++) - { - toporg[0] = origin[0] + xvals_top[j]; - toporg[1] = origin[1] + yvals_top[j]; - toporg[2] = plattop[2] + 16; - //get a grounded or swim area near the plat in the top position - area2num = AAS_PointAreaNum(toporg); - for (l = 0; l < 16; l++) - { - if (area2num) - { - if (AAS_AreaGrounded(area2num) || AAS_AreaSwim(area2num)) - { - VectorCopy(plattop, start); - start[2] += 32; - VectorCopy(toporg, end); - end[2] += 1; - trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, -1); - if (trace.fraction >= 1) break; - } //end if - } //end if - toporg[2] += 4; - area2num = AAS_PointAreaNum(toporg); - } //end if - //if in solid - if (l >= 16) continue; - //never create a reachability in the same area - if (area2num == area1num) continue; - //if the area isn't grounded - if (!AAS_AreaGrounded(area2num)) continue; - //if there already exists reachability between the areas - if (AAS_ReachabilityExists(area1num, area2num)) continue; - //if the reachability start is within the elevator bounding box - VectorSubtract(bottomorg, platbottom, dir); - VectorNormalize(dir); - dir[0] = bottomorg[0] + 24 * dir[0]; - dir[1] = bottomorg[1] + 24 * dir[1]; - dir[2] = bottomorg[2]; - // - for (p = 0; p < 3; p++) - if (dir[p] < origin[p] + mins[p] || dir[p] > origin[p] + maxs[p]) break; - if (p >= 3) continue; - //create a new reachability link - lreach = AAS_AllocReachability(); - if (!lreach) continue; - lreach->areanum = area2num; - //the facenum is the model number - lreach->facenum = modelnum; - //the edgenum is the height - lreach->edgenum = (int) height; - // - VectorCopy(dir, lreach->start); - VectorCopy(toporg, lreach->end); - lreach->traveltype = TRAVEL_ELEVATOR; - lreach->traveltype |= AAS_TravelFlagsForTeam(ent); - lreach->traveltime = aassettings.rs_startelevator + height * 100 / speed; - lreach->next = areareachability[area1num]; - areareachability[area1num] = lreach; - //don't go any further to the outside - n = 9999; - // -#ifdef REACH_DEBUG - Log_Write("elevator reach from %d to %d\r\n", area1num, area2num); -#endif //REACH_DEBUG - // - reach_elevator++; - } //end for - } //end for - } //end for - } //end if - } //end for -} //end of the function AAS_Reachability_Elevator -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -aas_lreachability_t *AAS_FindFaceReachabilities(vec3_t *facepoints, int numpoints, aas_plane_t *plane, int towardsface) -{ - int i, j, k, l; - int facenum, edgenum, bestfacenum; - float *v1, *v2, *v3, *v4; - float bestdist, speed, hordist, dist; - vec3_t beststart, beststart2, bestend, bestend2, tmp, hordir, testpoint; - aas_lreachability_t *lreach, *lreachabilities; - aas_area_t *area; - aas_face_t *face; - aas_edge_t *edge; - aas_plane_t *faceplane, *bestfaceplane; - - // - lreachabilities = NULL; - bestfacenum = 0; - bestfaceplane = NULL; - // - for (i = 1; i < aasworld.numareas; i++) - { - area = &aasworld.areas[i]; - // get the shortest distance between one of the func_bob start edges and - // one of the face edges of area1 - bestdist = 999999; - for (j = 0; j < area->numfaces; j++) - { - facenum = aasworld.faceindex[area->firstface + j]; - face = &aasworld.faces[abs(facenum)]; - //if not a ground face - if (!(face->faceflags & FACE_GROUND)) continue; - //get the ground planes - faceplane = &aasworld.planes[face->planenum]; - // - for (k = 0; k < face->numedges; k++) - { - edgenum = abs(aasworld.edgeindex[face->firstedge + k]); - edge = &aasworld.edges[edgenum]; - //calculate the minimum distance between the two edges - v1 = aasworld.vertexes[edge->v[0]]; - v2 = aasworld.vertexes[edge->v[1]]; - // - for (l = 0; l < numpoints; l++) - { - v3 = facepoints[l]; - v4 = facepoints[(l+1) % numpoints]; - dist = AAS_ClosestEdgePoints(v1, v2, v3, v4, faceplane, plane, - beststart, bestend, - beststart2, bestend2, bestdist); - if (dist < bestdist) - { - bestfacenum = facenum; - bestfaceplane = faceplane; - bestdist = dist; - } //end if - } //end for - } //end for - } //end for - // - if (bestdist > 192) continue; - // - VectorMiddle(beststart, beststart2, beststart); - VectorMiddle(bestend, bestend2, bestend); - // - if (!towardsface) - { - VectorCopy(beststart, tmp); - VectorCopy(bestend, beststart); - VectorCopy(tmp, bestend); - } //end if - // - VectorSubtract(bestend, beststart, hordir); - hordir[2] = 0; - hordist = VectorLength(hordir); - // - if (hordist > 2 * AAS_MaxJumpDistance(aassettings.phys_jumpvel)) continue; - //the end point should not be significantly higher than the start point - if (bestend[2] - 32 > beststart[2]) continue; - //don't fall down too far - if (bestend[2] < beststart[2] - 128) continue; - //the distance should not be too far - if (hordist > 32) - { - //check for walk off ledge - if (!AAS_HorizontalVelocityForJump(0, beststart, bestend, &speed)) continue; - } //end if - // - beststart[2] += 1; - bestend[2] += 1; - // - if (towardsface) VectorCopy(bestend, testpoint); - else VectorCopy(beststart, testpoint); - testpoint[2] = 0; - testpoint[2] = (bestfaceplane->dist - DotProduct(bestfaceplane->normal, testpoint)) / bestfaceplane->normal[2]; - // - if (!AAS_PointInsideFace(bestfacenum, testpoint, 0.1f)) - { - //if the faces are not overlapping then only go down - if (bestend[2] - 16 > beststart[2]) continue; - } //end if - lreach = AAS_AllocReachability(); - if (!lreach) return lreachabilities; - lreach->areanum = i; - lreach->facenum = 0; - lreach->edgenum = 0; - VectorCopy(beststart, lreach->start); - VectorCopy(bestend, lreach->end); - lreach->traveltype = 0; - lreach->traveltime = 0; - lreach->next = lreachabilities; - lreachabilities = lreach; -#ifndef BSPC - if (towardsface) AAS_PermanentLine(lreach->start, lreach->end, 1); - else AAS_PermanentLine(lreach->start, lreach->end, 2); -#endif - } //end for - return lreachabilities; -} //end of the function AAS_FindFaceReachabilities -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_Reachability_FuncBobbing(void) -{ - int ent, spawnflags, modelnum, axis; - int i, numareas, areas[10]; - char classname[MAX_EPAIRKEY], model[MAX_EPAIRKEY]; - vec3_t origin, move_end, move_start, move_start_top, move_end_top; - vec3_t mins, maxs, angles = {0, 0, 0}; - vec3_t start_edgeverts[4], end_edgeverts[4], mid; - vec3_t org, start, end, dir, points[10]; - float height; - aas_plane_t start_plane, end_plane; - aas_lreachability_t *startreach, *endreach, *nextstartreach, *nextendreach, *lreach; - aas_lreachability_t *firststartreach, *firstendreach; - - for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent)) - { - if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue; - if (strcmp(classname, "func_bobbing")) continue; - AAS_FloatForBSPEpairKey(ent, "height", &height); - if (!height) height = 32; - // - if (!AAS_ValueForBSPEpairKey(ent, "model", model, MAX_EPAIRKEY)) - { - botimport.Print(PRT_ERROR, "func_bobbing without model\n"); - continue; - } //end if - //get the model number, and skip the leading * - modelnum = atoi(model+1); - if (modelnum <= 0) - { - botimport.Print(PRT_ERROR, "func_bobbing with invalid model number\n"); - continue; - } //end if - //if the entity has an origin set then use it - if (!AAS_VectorForBSPEpairKey(ent, "origin", origin)) - VectorSet(origin, 0, 0, 0); - // - AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, NULL); - // - VectorAdd(mins, origin, mins); - VectorAdd(maxs, origin, maxs); - // - VectorAdd(mins, maxs, mid); - VectorScale(mid, 0.5, mid); - VectorCopy(mid, origin); - // - VectorCopy(origin, move_end); - VectorCopy(origin, move_start); - // - AAS_IntForBSPEpairKey(ent, "spawnflags", &spawnflags); - // set the axis of bobbing - if (spawnflags & 1) axis = 0; - else if (spawnflags & 2) axis = 1; - else axis = 2; - // - move_start[axis] -= height; - move_end[axis] += height; - // - Log_Write("funcbob model %d, start = {%1.1f, %1.1f, %1.1f} end = {%1.1f, %1.1f, %1.1f}\n", - modelnum, move_start[0], move_start[1], move_start[2], move_end[0], move_end[1], move_end[2]); - // -#ifndef BSPC - /* - AAS_DrawPermanentCross(move_start, 4, 1); - AAS_DrawPermanentCross(move_end, 4, 2); - */ -#endif - // - for (i = 0; i < 4; i++) - { - VectorCopy(move_start, start_edgeverts[i]); - start_edgeverts[i][2] += maxs[2] - mid[2]; //+ bbox maxs z - start_edgeverts[i][2] += 24; //+ player origin to ground dist - } //end for - start_edgeverts[0][0] += maxs[0] - mid[0]; - start_edgeverts[0][1] += maxs[1] - mid[1]; - start_edgeverts[1][0] += maxs[0] - mid[0]; - start_edgeverts[1][1] += mins[1] - mid[1]; - start_edgeverts[2][0] += mins[0] - mid[0]; - start_edgeverts[2][1] += mins[1] - mid[1]; - start_edgeverts[3][0] += mins[0] - mid[0]; - start_edgeverts[3][1] += maxs[1] - mid[1]; - // - start_plane.dist = start_edgeverts[0][2]; - VectorSet(start_plane.normal, 0, 0, 1); - // - for (i = 0; i < 4; i++) - { - VectorCopy(move_end, end_edgeverts[i]); - end_edgeverts[i][2] += maxs[2] - mid[2]; //+ bbox maxs z - end_edgeverts[i][2] += 24; //+ player origin to ground dist - } //end for - end_edgeverts[0][0] += maxs[0] - mid[0]; - end_edgeverts[0][1] += maxs[1] - mid[1]; - end_edgeverts[1][0] += maxs[0] - mid[0]; - end_edgeverts[1][1] += mins[1] - mid[1]; - end_edgeverts[2][0] += mins[0] - mid[0]; - end_edgeverts[2][1] += mins[1] - mid[1]; - end_edgeverts[3][0] += mins[0] - mid[0]; - end_edgeverts[3][1] += maxs[1] - mid[1]; - // - end_plane.dist = end_edgeverts[0][2]; - VectorSet(end_plane.normal, 0, 0, 1); - // -#ifndef BSPC -#if 0 - for (i = 0; i < 4; i++) - { - AAS_PermanentLine(start_edgeverts[i], start_edgeverts[(i+1)%4], 1); - AAS_PermanentLine(end_edgeverts[i], end_edgeverts[(i+1)%4], 1); - } //end for -#endif -#endif - VectorCopy(move_start, move_start_top); - move_start_top[2] += maxs[2] - mid[2] + 24; //+ bbox maxs z - VectorCopy(move_end, move_end_top); - move_end_top[2] += maxs[2] - mid[2] + 24; //+ bbox maxs z - // - if (!AAS_PointAreaNum(move_start_top)) continue; - if (!AAS_PointAreaNum(move_end_top)) continue; - // - for (i = 0; i < 2; i++) - { - firststartreach = firstendreach = NULL; - // - if (i == 0) - { - firststartreach = AAS_FindFaceReachabilities(start_edgeverts, 4, &start_plane, qtrue); - firstendreach = AAS_FindFaceReachabilities(end_edgeverts, 4, &end_plane, qfalse); - } //end if - else - { - firststartreach = AAS_FindFaceReachabilities(end_edgeverts, 4, &end_plane, qtrue); - firstendreach = AAS_FindFaceReachabilities(start_edgeverts, 4, &start_plane, qfalse); - } //end else - // - //create reachabilities from start to end - for (startreach = firststartreach; startreach; startreach = nextstartreach) - { - nextstartreach = startreach->next; - // - //trace = AAS_TraceClientBBox(startreach->start, move_start_top, PRESENCE_NORMAL, -1); - //if (trace.fraction < 1) continue; - // - for (endreach = firstendreach; endreach; endreach = nextendreach) - { - nextendreach = endreach->next; - // - //trace = AAS_TraceClientBBox(endreach->end, move_end_top, PRESENCE_NORMAL, -1); - //if (trace.fraction < 1) continue; - // - Log_Write("funcbob reach from area %d to %d\n", startreach->areanum, endreach->areanum); - // - // - if (i == 0) VectorCopy(move_start_top, org); - else VectorCopy(move_end_top, org); - VectorSubtract(startreach->start, org, dir); - dir[2] = 0; - VectorNormalize(dir); - VectorCopy(startreach->start, start); - VectorMA(startreach->start, 1, dir, start); - start[2] += 1; - VectorMA(startreach->start, 16, dir, end); - end[2] += 1; - // - numareas = AAS_TraceAreas(start, end, areas, points, 10); - if (numareas <= 0) continue; - if (numareas > 1) VectorCopy(points[1], startreach->start); - else VectorCopy(end, startreach->start); - // - if (!AAS_PointAreaNum(startreach->start)) continue; - if (!AAS_PointAreaNum(endreach->end)) continue; - // - lreach = AAS_AllocReachability(); - lreach->areanum = endreach->areanum; - if (i == 0) lreach->edgenum = ((int)move_start[axis] << 16) | ((int) move_end[axis] & 0x0000ffff); - else lreach->edgenum = ((int)move_end[axis] << 16) | ((int) move_start[axis] & 0x0000ffff); - lreach->facenum = (spawnflags << 16) | modelnum; - VectorCopy(startreach->start, lreach->start); - VectorCopy(endreach->end, lreach->end); -#ifndef BSPC -// AAS_DrawArrow(lreach->start, lreach->end, LINECOLOR_BLUE, LINECOLOR_YELLOW); -// AAS_PermanentLine(lreach->start, lreach->end, 1); -#endif - lreach->traveltype = TRAVEL_FUNCBOB; - lreach->traveltype |= AAS_TravelFlagsForTeam(ent); - lreach->traveltime = aassettings.rs_funcbob; - reach_funcbob++; - lreach->next = areareachability[startreach->areanum]; - areareachability[startreach->areanum] = lreach; - // - } //end for - } //end for - for (startreach = firststartreach; startreach; startreach = nextstartreach) - { - nextstartreach = startreach->next; - AAS_FreeReachability(startreach); - } //end for - for (endreach = firstendreach; endreach; endreach = nextendreach) - { - nextendreach = endreach->next; - AAS_FreeReachability(endreach); - } //end for - //only go up with func_bobbing entities that go up and down - if (!(spawnflags & 1) && !(spawnflags & 2)) break; - } //end for - } //end for -} //end of the function AAS_Reachability_FuncBobbing -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_Reachability_JumpPad(void) -{ - int face2num, i, ret, area2num, visualize, ent, bot_visualizejumppads; - //int modelnum, ent2; - //float dist, time, height, gravity, forward; - float speed, zvel, hordist; - aas_face_t *face2; - aas_area_t *area2; - aas_lreachability_t *lreach; - vec3_t areastart, facecenter, dir, cmdmove; - vec3_t velocity, absmins, absmaxs; - //vec3_t origin, ent2origin, angles, teststart; - aas_clientmove_t move; - //aas_trace_t trace; - aas_link_t *areas, *link; - //char target[MAX_EPAIRKEY], targetname[MAX_EPAIRKEY], model[MAX_EPAIRKEY]; - char classname[MAX_EPAIRKEY]; - -#ifdef BSPC - bot_visualizejumppads = 0; -#else - bot_visualizejumppads = LibVarValue("bot_visualizejumppads", "0"); -#endif - for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent)) - { - if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue; - if (strcmp(classname, "trigger_push")) continue; - // - if (!AAS_GetJumpPadInfo(ent, areastart, absmins, absmaxs, velocity)) continue; - /* - // - AAS_FloatForBSPEpairKey(ent, "speed", &speed); - if (!speed) speed = 1000; -// AAS_VectorForBSPEpairKey(ent, "angles", angles); -// AAS_SetMovedir(angles, velocity); -// VectorScale(velocity, speed, velocity); - VectorClear(angles); - //get the mins, maxs and origin of the model - AAS_ValueForBSPEpairKey(ent, "model", model, MAX_EPAIRKEY); - if (model[0]) modelnum = atoi(model+1); - else modelnum = 0; - AAS_BSPModelMinsMaxsOrigin(modelnum, angles, absmins, absmaxs, origin); - VectorAdd(origin, absmins, absmins); - VectorAdd(origin, absmaxs, absmaxs); - // -#ifdef REACH_DEBUG - botimport.Print(PRT_MESSAGE, "absmins = %f %f %f\n", absmins[0], absmins[1], absmins[2]); - botimport.Print(PRT_MESSAGE, "absmaxs = %f %f %f\n", absmaxs[0], absmaxs[1], absmaxs[2]); -#endif REACH_DEBUG - VectorAdd(absmins, absmaxs, origin); - VectorScale (origin, 0.5, origin); - - //get the start areas - VectorCopy(origin, teststart); - teststart[2] += 64; - trace = AAS_TraceClientBBox(teststart, origin, PRESENCE_CROUCH, -1); - if (trace.startsolid) - { - botimport.Print(PRT_MESSAGE, "trigger_push start solid\n"); - VectorCopy(origin, areastart); - } //end if - else - { - VectorCopy(trace.endpos, areastart); - } //end else - areastart[2] += 0.125; - // - //AAS_DrawPermanentCross(origin, 4, 4); - //get the target entity - AAS_ValueForBSPEpairKey(ent, "target", target, MAX_EPAIRKEY); - for (ent2 = AAS_NextBSPEntity(0); ent2; ent2 = AAS_NextBSPEntity(ent2)) - { - if (!AAS_ValueForBSPEpairKey(ent2, "targetname", targetname, MAX_EPAIRKEY)) continue; - if (!strcmp(targetname, target)) break; - } //end for - if (!ent2) - { - botimport.Print(PRT_MESSAGE, "trigger_push without target entity %s\n", target); - continue; - } //end if - AAS_VectorForBSPEpairKey(ent2, "origin", ent2origin); - // - height = ent2origin[2] - origin[2]; - gravity = aassettings.sv_gravity; - time = sqrt( height / ( 0.5 * gravity ) ); - if (!time) - { - botimport.Print(PRT_MESSAGE, "trigger_push without time\n"); - continue; - } //end if - // set s.origin2 to the push velocity - VectorSubtract ( ent2origin, origin, velocity); - dist = VectorNormalize( velocity); - forward = dist / time; - //FIXME: why multiply by 1.1 - forward *= 1.1; - VectorScale(velocity, forward, velocity); - velocity[2] = time * gravity; - */ - //get the areas the jump pad brush is in - areas = AAS_LinkEntityClientBBox(absmins, absmaxs, -1, PRESENCE_CROUCH); - /* - for (link = areas; link; link = link->next_area) - { - if (link->areanum == 563) - { - ret = qfalse; - } - } - */ - for (link = areas; link; link = link->next_area) - { - if (AAS_AreaJumpPad(link->areanum)) break; - } //end for - if (!link) - { - botimport.Print(PRT_MESSAGE, "trigger_push not in any jump pad area\n"); - AAS_UnlinkFromAreas(areas); - continue; - } //end if - // - botimport.Print(PRT_MESSAGE, "found a trigger_push with velocity %f %f %f\n", velocity[0], velocity[1], velocity[2]); - //if there is a horizontal velocity check for a reachability without air control - if (velocity[0] || velocity[1]) - { - VectorSet(cmdmove, 0, 0, 0); - //VectorCopy(velocity, cmdmove); - //cmdmove[2] = 0; - Com_Memset(&move, 0, sizeof(aas_clientmove_t)); - area2num = 0; - for (i = 0; i < 20; i++) - { - AAS_PredictClientMovement(&move, -1, areastart, PRESENCE_NORMAL, qfalse, - velocity, cmdmove, 0, 30, 0.1f, - SE_HITGROUND|SE_ENTERWATER|SE_ENTERSLIME| - SE_ENTERLAVA|SE_HITGROUNDDAMAGE|SE_TOUCHJUMPPAD|SE_TOUCHTELEPORTER, 0, bot_visualizejumppads); - area2num = move.endarea; - for (link = areas; link; link = link->next_area) - { - if (!AAS_AreaJumpPad(link->areanum)) continue; - if (link->areanum == area2num) break; - } //end if - if (!link) break; - VectorCopy(move.endpos, areastart); - VectorCopy(move.velocity, velocity); - } //end for - if (area2num && i < 20) - { - for (link = areas; link; link = link->next_area) - { - if (!AAS_AreaJumpPad(link->areanum)) continue; - if (AAS_ReachabilityExists(link->areanum, area2num)) continue; - //create a rocket or bfg jump reachability from area1 to area2 - lreach = AAS_AllocReachability(); - if (!lreach) - { - AAS_UnlinkFromAreas(areas); - return; - } //end if - lreach->areanum = area2num; - //NOTE: the facenum is the Z velocity - lreach->facenum = velocity[2]; - //NOTE: the edgenum is the horizontal velocity - lreach->edgenum = sqrt(velocity[0] * velocity[0] + velocity[1] * velocity[1]); - VectorCopy(areastart, lreach->start); - VectorCopy(move.endpos, lreach->end); - lreach->traveltype = TRAVEL_JUMPPAD; - lreach->traveltype |= AAS_TravelFlagsForTeam(ent); - lreach->traveltime = aassettings.rs_jumppad; - lreach->next = areareachability[link->areanum]; - areareachability[link->areanum] = lreach; - // - reach_jumppad++; - } //end for - } //end if - } //end if - // - if (fabs(velocity[0]) > 100 || fabs(velocity[1]) > 100) continue; - //check for areas we can reach with air control - for (area2num = 1; area2num < aasworld.numareas; area2num++) - { - visualize = qfalse; - /* - if (area2num == 3568) - { - for (link = areas; link; link = link->next_area) - { - if (link->areanum == 3380) - { - visualize = qtrue; - botimport.Print(PRT_MESSAGE, "bah\n"); - } //end if - } //end for - } //end if*/ - //never try to go back to one of the original jumppad areas - //and don't create reachabilities if they already exist - for (link = areas; link; link = link->next_area) - { - if (AAS_ReachabilityExists(link->areanum, area2num)) break; - if (AAS_AreaJumpPad(link->areanum)) - { - if (link->areanum == area2num) break; - } //end if - } //end if - if (link) continue; - // - area2 = &aasworld.areas[area2num]; - for (i = 0; i < area2->numfaces; i++) - { - face2num = aasworld.faceindex[area2->firstface + i]; - face2 = &aasworld.faces[abs(face2num)]; - //if it is not a ground face - if (!(face2->faceflags & FACE_GROUND)) continue; - //get the center of the face - AAS_FaceCenter(face2num, facecenter); - //only go higher up - if (facecenter[2] < areastart[2]) continue; - //get the jumppad jump z velocity - zvel = velocity[2]; - //get the horizontal speed for the jump, if it isn't possible to calculate this - //speed - ret = AAS_HorizontalVelocityForJump(zvel, areastart, facecenter, &speed); - if (ret && speed < 150) - { - //direction towards the face center - VectorSubtract(facecenter, areastart, dir); - dir[2] = 0; - hordist = VectorNormalize(dir); - //if (hordist < 1.6 * facecenter[2] - areastart[2]) - { - //get command movement - VectorScale(dir, speed, cmdmove); - // - AAS_PredictClientMovement(&move, -1, areastart, PRESENCE_NORMAL, qfalse, - velocity, cmdmove, 30, 30, 0.1f, - SE_ENTERWATER|SE_ENTERSLIME| - SE_ENTERLAVA|SE_HITGROUNDDAMAGE| - SE_TOUCHJUMPPAD|SE_TOUCHTELEPORTER|SE_HITGROUNDAREA, area2num, visualize); - //if prediction time wasn't enough to fully predict the movement - //don't enter slime or lava and don't fall from too high - if (move.frames < 30 && - !(move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA|SE_HITGROUNDDAMAGE)) - && (move.stopevent & (SE_HITGROUNDAREA|SE_TOUCHJUMPPAD|SE_TOUCHTELEPORTER))) - { - //never go back to the same jumppad - for (link = areas; link; link = link->next_area) - { - if (link->areanum == move.endarea) break; - } - if (!link) - { - for (link = areas; link; link = link->next_area) - { - if (!AAS_AreaJumpPad(link->areanum)) continue; - if (AAS_ReachabilityExists(link->areanum, area2num)) continue; - //create a jumppad reachability from area1 to area2 - lreach = AAS_AllocReachability(); - if (!lreach) - { - AAS_UnlinkFromAreas(areas); - return; - } //end if - lreach->areanum = move.endarea; - //NOTE: the facenum is the Z velocity - lreach->facenum = velocity[2]; - //NOTE: the edgenum is the horizontal velocity - lreach->edgenum = sqrt(cmdmove[0] * cmdmove[0] + cmdmove[1] * cmdmove[1]); - VectorCopy(areastart, lreach->start); - VectorCopy(facecenter, lreach->end); - lreach->traveltype = TRAVEL_JUMPPAD; - lreach->traveltype |= AAS_TravelFlagsForTeam(ent); - lreach->traveltime = aassettings.rs_aircontrolledjumppad; - lreach->next = areareachability[link->areanum]; - areareachability[link->areanum] = lreach; - // - reach_jumppad++; - } //end for - } - } //end if - } //end if - } //end for - } //end for - } //end for - AAS_UnlinkFromAreas(areas); - } //end for -} //end of the function AAS_Reachability_JumpPad -//=========================================================================== -// never point at ground faces -// always a higher and pretty far area -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_Reachability_Grapple(int area1num, int area2num) -{ - int face2num, i, j, areanum, numareas, areas[20]; - float mingrappleangle, z, hordist; - bsp_trace_t bsptrace; - aas_trace_t trace; - aas_face_t *face2; - aas_area_t *area1, *area2; - aas_lreachability_t *lreach; - vec3_t areastart, facecenter, start, end, dir, down = {0, 0, -1}; - vec_t *v; - - //only grapple when on the ground or swimming - if (!AAS_AreaGrounded(area1num) && !AAS_AreaSwim(area1num)) return qfalse; - //don't grapple from a crouch area - if (!(AAS_AreaPresenceType(area1num) & PRESENCE_NORMAL)) return qfalse; - //NOTE: disabled area swim it doesn't work right - if (AAS_AreaSwim(area1num)) return qfalse; - // - area1 = &aasworld.areas[area1num]; - area2 = &aasworld.areas[area2num]; - //don't grapple towards way lower areas - if (area2->maxs[2] < area1->mins[2]) return qfalse; - // - VectorCopy(aasworld.areas[area1num].center, start); - //if not a swim area - if (!AAS_AreaSwim(area1num)) - { - if (!AAS_PointAreaNum(start)) Log_Write("area %d center %f %f %f in solid?\r\n", area1num, - start[0], start[1], start[2]); - VectorCopy(start, end); - end[2] -= 1000; - trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, -1); - if (trace.startsolid) return qfalse; - VectorCopy(trace.endpos, areastart); - } //end if - else - { - if (!(AAS_PointContents(start) & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER))) return qfalse; - } //end else - // - //start is now the start point - // - for (i = 0; i < area2->numfaces; i++) - { - face2num = aasworld.faceindex[area2->firstface + i]; - face2 = &aasworld.faces[abs(face2num)]; - //if it is not a solid face - if (!(face2->faceflags & FACE_SOLID)) continue; - //direction towards the first vertex of the face - v = aasworld.vertexes[aasworld.edges[abs(aasworld.edgeindex[face2->firstedge])].v[0]]; - VectorSubtract(v, areastart, dir); - //if the face plane is facing away - if (DotProduct(aasworld.planes[face2->planenum].normal, dir) > 0) continue; - //get the center of the face - AAS_FaceCenter(face2num, facecenter); - //only go higher up with the grapple - if (facecenter[2] < areastart[2] + 64) continue; - //only use vertical faces or downward facing faces - if (DotProduct(aasworld.planes[face2->planenum].normal, down) < 0) continue; - //direction towards the face center - VectorSubtract(facecenter, areastart, dir); - // - z = dir[2]; - dir[2] = 0; - hordist = VectorLength(dir); - if (!hordist) continue; - //if too far - if (hordist > 2000) continue; - //check the minimal angle of the movement - mingrappleangle = 15; //15 degrees - if (z / hordist < tan(2 * M_PI * mingrappleangle / 360)) continue; - // - VectorCopy(facecenter, start); - VectorMA(facecenter, -500, aasworld.planes[face2->planenum].normal, end); - // - bsptrace = AAS_Trace(start, NULL, NULL, end, 0, CONTENTS_SOLID); - //the grapple won't stick to the sky and the grapple point should be near the AAS wall - if ((bsptrace.surface.flags & SURF_SKY) || (bsptrace.fraction * 500 > 32)) continue; - //trace a full bounding box from the area center on the ground to - //the center of the face - VectorSubtract(facecenter, areastart, dir); - VectorNormalize(dir); - VectorMA(areastart, 4, dir, start); - VectorCopy(bsptrace.endpos, end); - trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, -1); - VectorSubtract(trace.endpos, facecenter, dir); - if (VectorLength(dir) > 24) continue; - // - VectorCopy(trace.endpos, start); - VectorCopy(trace.endpos, end); - end[2] -= AAS_FallDamageDistance(); - trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, -1); - if (trace.fraction >= 1) continue; - //area to end in - areanum = AAS_PointAreaNum(trace.endpos); - //if not in lava or slime - if (aasworld.areasettings[areanum].contents & (AREACONTENTS_SLIME|AREACONTENTS_LAVA)) - { - continue; - } //end if - //do not go the the source area - if (areanum == area1num) continue; - //don't create reachabilities if they already exist - if (AAS_ReachabilityExists(area1num, areanum)) continue; - //only end in areas we can stand - if (!AAS_AreaGrounded(areanum)) continue; - //never go through cluster portals!! - numareas = AAS_TraceAreas(areastart, bsptrace.endpos, areas, NULL, 20); - if (numareas >= 20) continue; - for (j = 0; j < numareas; j++) - { - if (aasworld.areasettings[areas[j]].contents & AREACONTENTS_CLUSTERPORTAL) break; - } //end for - if (j < numareas) continue; - //create a new reachability link - lreach = AAS_AllocReachability(); - if (!lreach) return qfalse; - lreach->areanum = areanum; - lreach->facenum = face2num; - lreach->edgenum = 0; - VectorCopy(areastart, lreach->start); - //VectorCopy(facecenter, lreach->end); - VectorCopy(bsptrace.endpos, lreach->end); - lreach->traveltype = TRAVEL_GRAPPLEHOOK; - VectorSubtract(lreach->end, lreach->start, dir); - lreach->traveltime = aassettings.rs_startgrapple + VectorLength(dir) * 0.25; - lreach->next = areareachability[area1num]; - areareachability[area1num] = lreach; - // - reach_grapple++; - } //end for - // - return qfalse; -} //end of the function AAS_Reachability_Grapple -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_SetWeaponJumpAreaFlags(void) -{ - int ent, i; - vec3_t mins = {-15, -15, -15}, maxs = {15, 15, 15}; - vec3_t origin; - int areanum, weaponjumpareas, spawnflags; - char classname[MAX_EPAIRKEY]; - - weaponjumpareas = 0; - for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent)) - { - if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue; - if ( - !strcmp(classname, "item_armor_body") || - !strcmp(classname, "item_armor_combat") || - !strcmp(classname, "item_health_mega") || - !strcmp(classname, "weapon_grenadelauncher") || - !strcmp(classname, "weapon_rocketlauncher") || - !strcmp(classname, "weapon_lightning") || - !strcmp(classname, "weapon_plasmagun") || - !strcmp(classname, "weapon_railgun") || - !strcmp(classname, "weapon_bfg") || - !strcmp(classname, "item_quad") || - !strcmp(classname, "item_regen") || - !strcmp(classname, "item_invulnerability")) - { - if (AAS_VectorForBSPEpairKey(ent, "origin", origin)) - { - spawnflags = 0; - AAS_IntForBSPEpairKey(ent, "spawnflags", &spawnflags); - //if not a stationary item - if (!(spawnflags & 1)) - { - if (!AAS_DropToFloor(origin, mins, maxs)) - { - botimport.Print(PRT_MESSAGE, "%s in solid at (%1.1f %1.1f %1.1f)\n", - classname, origin[0], origin[1], origin[2]); - } //end if - } //end if - //areanum = AAS_PointAreaNum(origin); - areanum = AAS_BestReachableArea(origin, mins, maxs, origin); - //the bot may rocket jump towards this area - aasworld.areasettings[areanum].areaflags |= AREA_WEAPONJUMP; - // - //if (!AAS_AreaGrounded(areanum)) - // botimport.Print(PRT_MESSAGE, "area not grounded\n"); - // - weaponjumpareas++; - } //end if - } //end if - } //end for - for (i = 1; i < aasworld.numareas; i++) - { - if (aasworld.areasettings[i].contents & AREACONTENTS_JUMPPAD) - { - aasworld.areasettings[i].areaflags |= AREA_WEAPONJUMP; - weaponjumpareas++; - } //end if - } //end for - botimport.Print(PRT_MESSAGE, "%d weapon jump areas\n", weaponjumpareas); -} //end of the function AAS_SetWeaponJumpAreaFlags -//=========================================================================== -// create a possible weapon jump reachability from area1 to area2 -// -// check if there's a cool item in the second area -// check if area1 is lower than area2 -// check if the bot can rocketjump from area1 to area2 -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_Reachability_WeaponJump(int area1num, int area2num) -{ - int face2num, i, n, ret, visualize; - float speed, zvel, hordist; - aas_face_t *face2; - aas_area_t *area1, *area2; - aas_lreachability_t *lreach; - vec3_t areastart, facecenter, start, end, dir, cmdmove;// teststart; - vec3_t velocity; - aas_clientmove_t move; - aas_trace_t trace; - - visualize = qfalse; -// if (area1num == 4436 && area2num == 4318) -// { -// visualize = qtrue; -// } - if (!AAS_AreaGrounded(area1num) || AAS_AreaSwim(area1num)) return qfalse; - if (!AAS_AreaGrounded(area2num)) return qfalse; - //NOTE: only weapon jump towards areas with an interesting item in it?? - if (!(aasworld.areasettings[area2num].areaflags & AREA_WEAPONJUMP)) return qfalse; - // - area1 = &aasworld.areas[area1num]; - area2 = &aasworld.areas[area2num]; - //don't weapon jump towards way lower areas - if (area2->maxs[2] < area1->mins[2]) return qfalse; - // - VectorCopy(aasworld.areas[area1num].center, start); - //if not a swim area - if (!AAS_PointAreaNum(start)) Log_Write("area %d center %f %f %f in solid?\r\n", area1num, - start[0], start[1], start[2]); - VectorCopy(start, end); - end[2] -= 1000; - trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, -1); - if (trace.startsolid) return qfalse; - VectorCopy(trace.endpos, areastart); - // - //areastart is now the start point - // - for (i = 0; i < area2->numfaces; i++) - { - face2num = aasworld.faceindex[area2->firstface + i]; - face2 = &aasworld.faces[abs(face2num)]; - //if it is not a solid face - if (!(face2->faceflags & FACE_GROUND)) continue; - //get the center of the face - AAS_FaceCenter(face2num, facecenter); - //only go higher up with weapon jumps - if (facecenter[2] < areastart[2] + 64) continue; - //NOTE: set to 2 to allow bfg jump reachabilities - for (n = 0; n < 1/*2*/; n++) - { - //get the rocket jump z velocity - if (n) zvel = AAS_BFGJumpZVelocity(areastart); - else zvel = AAS_RocketJumpZVelocity(areastart); - //get the horizontal speed for the jump, if it isn't possible to calculate this - //speed (the jump is not possible) then there's no jump reachability created - ret = AAS_HorizontalVelocityForJump(zvel, areastart, facecenter, &speed); - if (ret && speed < 300) - { - //direction towards the face center - VectorSubtract(facecenter, areastart, dir); - dir[2] = 0; - hordist = VectorNormalize(dir); - //if (hordist < 1.6 * (facecenter[2] - areastart[2])) - { - //get command movement - VectorScale(dir, speed, cmdmove); - VectorSet(velocity, 0, 0, zvel); - /* - //get command movement - VectorScale(dir, speed, velocity); - velocity[2] = zvel; - VectorSet(cmdmove, 0, 0, 0); - */ - // - AAS_PredictClientMovement(&move, -1, areastart, PRESENCE_NORMAL, qtrue, - velocity, cmdmove, 30, 30, 0.1f, - SE_ENTERWATER|SE_ENTERSLIME| - SE_ENTERLAVA|SE_HITGROUNDDAMAGE| - SE_TOUCHJUMPPAD|SE_HITGROUND|SE_HITGROUNDAREA, area2num, visualize); - //if prediction time wasn't enough to fully predict the movement - //don't enter slime or lava and don't fall from too high - if (move.frames < 30 && - !(move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA|SE_HITGROUNDDAMAGE)) - && (move.stopevent & (SE_HITGROUNDAREA|SE_TOUCHJUMPPAD))) - { - //create a rocket or bfg jump reachability from area1 to area2 - lreach = AAS_AllocReachability(); - if (!lreach) return qfalse; - lreach->areanum = area2num; - lreach->facenum = 0; - lreach->edgenum = 0; - VectorCopy(areastart, lreach->start); - VectorCopy(facecenter, lreach->end); - if (n) - { - lreach->traveltype = TRAVEL_BFGJUMP; - lreach->traveltime = aassettings.rs_bfgjump; - } //end if - else - { - lreach->traveltype = TRAVEL_ROCKETJUMP; - lreach->traveltime = aassettings.rs_rocketjump; - } //end else - lreach->next = areareachability[area1num]; - areareachability[area1num] = lreach; - // - reach_rocketjump++; - return qtrue; - } //end if - } //end if - } //end if - } //end for - } //end for - // - return qfalse; -} //end of the function AAS_Reachability_WeaponJump -//=========================================================================== -// calculates additional walk off ledge reachabilities for the given area -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_Reachability_WalkOffLedge(int areanum) -{ - int i, j, k, l, m, n, p, areas[10], numareas; - int face1num, face2num, face3num, edge1num, edge2num, edge3num; - int otherareanum, gap, reachareanum, side; - aas_area_t *area, *area2; - aas_face_t *face1, *face2, *face3; - aas_edge_t *edge; - aas_plane_t *plane; - vec_t *v1, *v2; - vec3_t sharededgevec, mid, dir, testend; - aas_lreachability_t *lreach; - aas_trace_t trace; - - if (!AAS_AreaGrounded(areanum) || AAS_AreaSwim(areanum)) return; - // - area = &aasworld.areas[areanum]; - // - for (i = 0; i < area->numfaces; i++) - { - face1num = aasworld.faceindex[area->firstface + i]; - face1 = &aasworld.faces[abs(face1num)]; - //face 1 must be a ground face - if (!(face1->faceflags & FACE_GROUND)) continue; - //go through all the edges of this ground face - for (k = 0; k < face1->numedges; k++) - { - edge1num = aasworld.edgeindex[face1->firstedge + k]; - //find another not ground face using this same edge - for (j = 0; j < area->numfaces; j++) - { - face2num = aasworld.faceindex[area->firstface + j]; - face2 = &aasworld.faces[abs(face2num)]; - //face 2 may not be a ground face - if (face2->faceflags & FACE_GROUND) continue; - //compare all the edges - for (l = 0; l < face2->numedges; l++) - { - edge2num = aasworld.edgeindex[face2->firstedge + l]; - if (abs(edge1num) == abs(edge2num)) - { - //get the area at the other side of the face - if (face2->frontarea == areanum) otherareanum = face2->backarea; - else otherareanum = face2->frontarea; - // - area2 = &aasworld.areas[otherareanum]; - //if the other area is grounded! - if (aasworld.areasettings[otherareanum].areaflags & AREA_GROUNDED) - { - //check for a possible gap - gap = qfalse; - for (n = 0; n < area2->numfaces; n++) - { - face3num = aasworld.faceindex[area2->firstface + n]; - //may not be the shared face of the two areas - if (abs(face3num) == abs(face2num)) continue; - // - face3 = &aasworld.faces[abs(face3num)]; - //find an edge shared by all three faces - for (m = 0; m < face3->numedges; m++) - { - edge3num = aasworld.edgeindex[face3->firstedge + m]; - //but the edge should be shared by all three faces - if (abs(edge3num) == abs(edge1num)) - { - if (!(face3->faceflags & FACE_SOLID)) - { - gap = qtrue; - break; - } //end if - // - if (face3->faceflags & FACE_GROUND) - { - gap = qfalse; - break; - } //end if - //FIXME: there are more situations to be handled - gap = qtrue; - break; - } //end if - } //end for - if (m < face3->numedges) break; - } //end for - if (!gap) break; - } //end if - //check for a walk off ledge reachability - edge = &aasworld.edges[abs(edge1num)]; - side = edge1num < 0; - // - v1 = aasworld.vertexes[edge->v[side]]; - v2 = aasworld.vertexes[edge->v[!side]]; - // - plane = &aasworld.planes[face1->planenum]; - //get the points really into the areas - VectorSubtract(v2, v1, sharededgevec); - CrossProduct(plane->normal, sharededgevec, dir); - VectorNormalize(dir); - // - VectorAdd(v1, v2, mid); - VectorScale(mid, 0.5, mid); - VectorMA(mid, 8, dir, mid); - // - VectorCopy(mid, testend); - testend[2] -= 1000; - trace = AAS_TraceClientBBox(mid, testend, PRESENCE_CROUCH, -1); - // - if (trace.startsolid) - { - //Log_Write("area %d: trace.startsolid\r\n", areanum); - break; - } //end if - reachareanum = AAS_PointAreaNum(trace.endpos); - if (reachareanum == areanum) - { - //Log_Write("area %d: same area\r\n", areanum); - break; - } //end if - if (AAS_ReachabilityExists(areanum, reachareanum)) - { - //Log_Write("area %d: reachability already exists\r\n", areanum); - break; - } //end if - if (!AAS_AreaGrounded(reachareanum) && !AAS_AreaSwim(reachareanum)) - { - //Log_Write("area %d, reach area %d: not grounded and not swim\r\n", areanum, reachareanum); - break; - } //end if - // - if (aasworld.areasettings[reachareanum].contents & (AREACONTENTS_SLIME - | AREACONTENTS_LAVA)) - { - //Log_Write("area %d, reach area %d: lava or slime\r\n", areanum, reachareanum); - break; - } //end if - //if not going through a cluster portal - numareas = AAS_TraceAreas(mid, testend, areas, NULL, sizeof(areas) / sizeof(int)); - for (p = 0; p < numareas; p++) - if (AAS_AreaClusterPortal(areas[p])) - break; - if (p < numareas) - break; - // if a maximum fall height is set and the bot would fall down further - if (aassettings.rs_maxfallheight && fabs(mid[2] - trace.endpos[2]) > aassettings.rs_maxfallheight) - break; - // - lreach = AAS_AllocReachability(); - if (!lreach) break; - lreach->areanum = reachareanum; - lreach->facenum = 0; - lreach->edgenum = edge1num; - VectorCopy(mid, lreach->start); - VectorCopy(trace.endpos, lreach->end); - lreach->traveltype = TRAVEL_WALKOFFLEDGE; - lreach->traveltime = aassettings.rs_startwalkoffledge + fabs(mid[2] - trace.endpos[2]) * 50 / aassettings.phys_gravity; - if (!AAS_AreaSwim(reachareanum) && !AAS_AreaJumpPad(reachareanum)) - { - if (AAS_FallDelta(mid[2] - trace.endpos[2]) > aassettings.phys_falldelta5) - { - lreach->traveltime += aassettings.rs_falldamage5; - } //end if - else if (AAS_FallDelta(mid[2] - trace.endpos[2]) > aassettings.phys_falldelta10) - { - lreach->traveltime += aassettings.rs_falldamage10; - } //end if - } //end if - lreach->next = areareachability[areanum]; - areareachability[areanum] = lreach; - //we've got another walk off ledge reachability - reach_walkoffledge++; - } //end if - } //end for - } //end for - } //end for - } //end for -} //end of the function AAS_Reachability_WalkOffLedge -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_StoreReachability(void) -{ - int i; - aas_areasettings_t *areasettings; - aas_lreachability_t *lreach; - aas_reachability_t *reach; - - if (aasworld.reachability) FreeMemory(aasworld.reachability); - aasworld.reachability = (aas_reachability_t *) GetClearedMemory((numlreachabilities + 10) * sizeof(aas_reachability_t)); - aasworld.reachabilitysize = 1; - for (i = 0; i < aasworld.numareas; i++) - { - areasettings = &aasworld.areasettings[i]; - areasettings->firstreachablearea = aasworld.reachabilitysize; - areasettings->numreachableareas = 0; - for (lreach = areareachability[i]; lreach; lreach = lreach->next) - { - reach = &aasworld.reachability[areasettings->firstreachablearea + - areasettings->numreachableareas]; - reach->areanum = lreach->areanum; - reach->facenum = lreach->facenum; - reach->edgenum = lreach->edgenum; - VectorCopy(lreach->start, reach->start); - VectorCopy(lreach->end, reach->end); - reach->traveltype = lreach->traveltype; - reach->traveltime = lreach->traveltime; - // - areasettings->numreachableareas++; - } //end for - aasworld.reachabilitysize += areasettings->numreachableareas; - } //end for -} //end of the function AAS_StoreReachability -//=========================================================================== -// -// TRAVEL_WALK 100% equal floor height + steps -// TRAVEL_CROUCH 100% -// TRAVEL_BARRIERJUMP 100% -// TRAVEL_JUMP 80% -// TRAVEL_LADDER 100% + fall down from ladder + jump up to ladder -// TRAVEL_WALKOFFLEDGE 90% walk off very steep walls? -// TRAVEL_SWIM 100% -// TRAVEL_WATERJUMP 100% -// TRAVEL_TELEPORT 100% -// TRAVEL_ELEVATOR 100% -// TRAVEL_GRAPPLEHOOK 100% -// TRAVEL_DOUBLEJUMP 0% -// TRAVEL_RAMPJUMP 0% -// TRAVEL_STRAFEJUMP 0% -// TRAVEL_ROCKETJUMP 100% (currently limited towards areas with items) -// TRAVEL_BFGJUMP 0% (currently disabled) -// TRAVEL_JUMPPAD 100% -// TRAVEL_FUNCBOB 100% -// -// Parameter: - -// Returns: true if NOT finished -// Changes Globals: - -//=========================================================================== -int AAS_ContinueInitReachability(float time) -{ - int i, j, todo, start_time; - static float framereachability, reachability_delay; - static int lastpercentage; - - if (!aasworld.loaded) return qfalse; - //if reachability is calculated for all areas - if (aasworld.numreachabilityareas >= aasworld.numareas + 2) return qfalse; - //if starting with area 1 (area 0 is a dummy) - if (aasworld.numreachabilityareas == 1) - { - botimport.Print(PRT_MESSAGE, "calculating reachability...\n"); - lastpercentage = 0; - framereachability = 2000; - reachability_delay = 1000; - } //end if - //number of areas to calculate reachability for this cycle - todo = aasworld.numreachabilityareas + (int) framereachability; - start_time = Sys_MilliSeconds(); - //loop over the areas - for (i = aasworld.numreachabilityareas; i < aasworld.numareas && i < todo; i++) - { - aasworld.numreachabilityareas++; - //only create jumppad reachabilities from jumppad areas - if (aasworld.areasettings[i].contents & AREACONTENTS_JUMPPAD) - { - continue; - } //end if - //loop over the areas - for (j = 1; j < aasworld.numareas; j++) - { - if (i == j) continue; - //never create reachabilities from teleporter or jumppad areas to regular areas - if (aasworld.areasettings[i].contents & (AREACONTENTS_TELEPORTER|AREACONTENTS_JUMPPAD)) - { - if (!(aasworld.areasettings[j].contents & (AREACONTENTS_TELEPORTER|AREACONTENTS_JUMPPAD))) - { - continue; - } //end if - } //end if - //if there already is a reachability link from area i to j - if (AAS_ReachabilityExists(i, j)) continue; - //check for a swim reachability - if (AAS_Reachability_Swim(i, j)) continue; - //check for a simple walk on equal floor height reachability - if (AAS_Reachability_EqualFloorHeight(i, j)) continue; - //check for step, barrier, waterjump and walk off ledge reachabilities - if (AAS_Reachability_Step_Barrier_WaterJump_WalkOffLedge(i, j)) continue; - //check for ladder reachabilities - if (AAS_Reachability_Ladder(i, j)) continue; - //check for a jump reachability - if (AAS_Reachability_Jump(i, j)) continue; - } //end for - //never create these reachabilities from teleporter or jumppad areas - if (aasworld.areasettings[i].contents & (AREACONTENTS_TELEPORTER|AREACONTENTS_JUMPPAD)) - { - continue; - } //end if - //loop over the areas - for (j = 1; j < aasworld.numareas; j++) - { - if (i == j) continue; - // - if (AAS_ReachabilityExists(i, j)) continue; - //check for a grapple hook reachability - if (calcgrapplereach) AAS_Reachability_Grapple(i, j); - //check for a weapon jump reachability - AAS_Reachability_WeaponJump(i, j); - } //end for - //if the calculation took more time than the max reachability delay - if (Sys_MilliSeconds() - start_time > (int) reachability_delay) break; - // - if (aasworld.numreachabilityareas * 1000 / aasworld.numareas > lastpercentage) break; - } //end for - // - if (aasworld.numreachabilityareas == aasworld.numareas) - { - botimport.Print(PRT_MESSAGE, "\r%6.1f%%", (float) 100.0); - botimport.Print(PRT_MESSAGE, "\nplease wait while storing reachability...\n"); - aasworld.numreachabilityareas++; - } //end if - //if this is the last step in the reachability calculations - else if (aasworld.numreachabilityareas == aasworld.numareas + 1) - { - //create additional walk off ledge reachabilities for every area - for (i = 1; i < aasworld.numareas; i++) - { - //only create jumppad reachabilities from jumppad areas - if (aasworld.areasettings[i].contents & AREACONTENTS_JUMPPAD) - { - continue; - } //end if - AAS_Reachability_WalkOffLedge(i); - } //end for - //create jump pad reachabilities - AAS_Reachability_JumpPad(); - //create teleporter reachabilities - AAS_Reachability_Teleport(); - //create elevator (func_plat) reachabilities - AAS_Reachability_Elevator(); - //create func_bobbing reachabilities - AAS_Reachability_FuncBobbing(); - // -#ifdef DEBUG - botimport.Print(PRT_MESSAGE, "%6d reach swim\n", reach_swim); - botimport.Print(PRT_MESSAGE, "%6d reach equal floor\n", reach_equalfloor); - botimport.Print(PRT_MESSAGE, "%6d reach step\n", reach_step); - botimport.Print(PRT_MESSAGE, "%6d reach barrier\n", reach_barrier); - botimport.Print(PRT_MESSAGE, "%6d reach waterjump\n", reach_waterjump); - botimport.Print(PRT_MESSAGE, "%6d reach walkoffledge\n", reach_walkoffledge); - botimport.Print(PRT_MESSAGE, "%6d reach jump\n", reach_jump); - botimport.Print(PRT_MESSAGE, "%6d reach ladder\n", reach_ladder); - botimport.Print(PRT_MESSAGE, "%6d reach walk\n", reach_walk); - botimport.Print(PRT_MESSAGE, "%6d reach teleport\n", reach_teleport); - botimport.Print(PRT_MESSAGE, "%6d reach funcbob\n", reach_funcbob); - botimport.Print(PRT_MESSAGE, "%6d reach elevator\n", reach_elevator); - botimport.Print(PRT_MESSAGE, "%6d reach grapple\n", reach_grapple); - botimport.Print(PRT_MESSAGE, "%6d reach rocketjump\n", reach_rocketjump); - botimport.Print(PRT_MESSAGE, "%6d reach jumppad\n", reach_jumppad); -#endif - //*/ - //store all the reachabilities - AAS_StoreReachability(); - //free the reachability link heap - AAS_ShutDownReachabilityHeap(); - // - FreeMemory(areareachability); - // - aasworld.numreachabilityareas++; - // - botimport.Print(PRT_MESSAGE, "calculating clusters...\n"); - } //end if - else - { - lastpercentage = aasworld.numreachabilityareas * 1000 / aasworld.numareas; - botimport.Print(PRT_MESSAGE, "\r%6.1f%%", (float) lastpercentage / 10); - } //end else - //not yet finished - return qtrue; -} //end of the function AAS_ContinueInitReachability -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_InitReachability(void) -{ - if (!aasworld.loaded) return; - - if (aasworld.reachabilitysize) - { -#ifndef BSPC - if (!((int)LibVarGetValue("forcereachability"))) - { - aasworld.numreachabilityareas = aasworld.numareas + 2; - return; - } //end if -#else - aasworld.numreachabilityareas = aasworld.numareas + 2; - return; -#endif //BSPC - } //end if -#ifndef BSPC - calcgrapplereach = LibVarGetValue("grapplereach"); -#endif - aasworld.savefile = qtrue; - //start with area 1 because area zero is a dummy - aasworld.numreachabilityareas = 1; - ////aasworld.numreachabilityareas = aasworld.numareas + 1; //only calculate entity reachabilities - //setup the heap with reachability links - AAS_SetupReachabilityHeap(); - //allocate area reachability link array - areareachability = (aas_lreachability_t **) GetClearedMemory( - aasworld.numareas * sizeof(aas_lreachability_t *)); - // - AAS_SetWeaponJumpAreaFlags(); -} //end of the function AAS_InitReachable diff --git a/src/botlib/be_aas_reach.h b/src/botlib/be_aas_reach.h deleted file mode 100644 index f64114af..00000000 --- a/src/botlib/be_aas_reach.h +++ /dev/null @@ -1,69 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_aas_reach.h - * - * desc: AAS - * - * $Archive: /source/code/botlib/be_aas_reach.h $ - * - *****************************************************************************/ - -#ifdef AASINTERN -//initialize calculating the reachabilities -void AAS_InitReachability(void); -//continue calculating the reachabilities -int AAS_ContinueInitReachability(float time); -// -int AAS_BestReachableLinkArea(aas_link_t *areas); -#endif //AASINTERN - -//returns true if the are has reachabilities to other areas -int AAS_AreaReachability(int areanum); -//returns the best reachable area and goal origin for a bounding box at the given origin -int AAS_BestReachableArea(vec3_t origin, vec3_t mins, vec3_t maxs, vec3_t goalorigin); -//returns the best jumppad area from which the bbox at origin is reachable -int AAS_BestReachableFromJumpPadArea(vec3_t origin, vec3_t mins, vec3_t maxs); -//returns the next reachability using the given model -int AAS_NextModelReachability(int num, int modelnum); -//returns the total area of the ground faces of the given area -float AAS_AreaGroundFaceArea(int areanum); -//returns true if the area is crouch only -int AAS_AreaCrouch(int areanum); -//returns true if a player can swim in this area -int AAS_AreaSwim(int areanum); -//returns true if the area is filled with a liquid -int AAS_AreaLiquid(int areanum); -//returns true if the area contains lava -int AAS_AreaLava(int areanum); -//returns true if the area contains slime -int AAS_AreaSlime(int areanum); -//returns true if the area has one or more ground faces -int AAS_AreaGrounded(int areanum); -//returns true if the area has one or more ladder faces -int AAS_AreaLadder(int areanum); -//returns true if the area is a jump pad -int AAS_AreaJumpPad(int areanum); -//returns true if the area is donotenter -int AAS_AreaDoNotEnter(int areanum); diff --git a/src/botlib/be_aas_route.c b/src/botlib/be_aas_route.c deleted file mode 100644 index f623ae40..00000000 --- a/src/botlib/be_aas_route.c +++ /dev/null @@ -1,2211 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_aas_route.c - * - * desc: AAS - * - * $Archive: /MissionPack/code/botlib/be_aas_route.c $ - * - *****************************************************************************/ - -#include "../qcommon/q_shared.h" -#include "l_utils.h" -#include "l_memory.h" -#include "l_log.h" -#include "l_crc.h" -#include "l_libvar.h" -#include "l_script.h" -#include "l_precomp.h" -#include "l_struct.h" -#include "aasfile.h" -#include "botlib.h" -#include "be_aas.h" -#include "be_aas_funcs.h" -#include "be_interface.h" -#include "be_aas_def.h" - -#define ROUTING_DEBUG - -//travel time in hundreths of a second = distance * 100 / speed -#define DISTANCEFACTOR_CROUCH 1.3f //crouch speed = 100 -#define DISTANCEFACTOR_SWIM 1 //should be 0.66, swim speed = 150 -#define DISTANCEFACTOR_WALK 0.33f //walk speed = 300 - -//cache refresh time -#define CACHE_REFRESHTIME 15.0f //15 seconds refresh time - -//maximum number of routing updates each frame -#define MAX_FRAMEROUTINGUPDATES 10 - - -/* - - area routing cache: - stores the distances within one cluster to a specific goal area - this goal area is in this same cluster and could be a cluster portal - for every cluster there's a list with routing cache for every area - in that cluster (including the portals of that cluster) - area cache stores aasworld.clusters[?].numreachabilityareas travel times - - portal routing cache: - stores the distances of all portals to a specific goal area - this goal area could be in any cluster and could also be a cluster portal - for every area (aasworld.numareas) the portal cache stores - aasworld.numportals travel times - -*/ - -#ifdef ROUTING_DEBUG -int numareacacheupdates; -int numportalcacheupdates; -#endif //ROUTING_DEBUG - -int routingcachesize; -int max_routingcachesize; - -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -#ifdef ROUTING_DEBUG -void AAS_RoutingInfo(void) -{ - botimport.Print(PRT_MESSAGE, "%d area cache updates\n", numareacacheupdates); - botimport.Print(PRT_MESSAGE, "%d portal cache updates\n", numportalcacheupdates); - botimport.Print(PRT_MESSAGE, "%d bytes routing cache\n", routingcachesize); -} //end of the function AAS_RoutingInfo -#endif //ROUTING_DEBUG -//=========================================================================== -// returns the number of the area in the cluster -// assumes the given area is in the given cluster or a portal of the cluster -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -ID_INLINE int AAS_ClusterAreaNum(int cluster, int areanum) -{ - int side, areacluster; - - areacluster = aasworld.areasettings[areanum].cluster; - if (areacluster > 0) return aasworld.areasettings[areanum].clusterareanum; - else - { -/*#ifdef ROUTING_DEBUG - if (aasworld.portals[-areacluster].frontcluster != cluster && - aasworld.portals[-areacluster].backcluster != cluster) - { - botimport.Print(PRT_ERROR, "portal %d: does not belong to cluster %d\n" - , -areacluster, cluster); - } //end if -#endif //ROUTING_DEBUG*/ - side = aasworld.portals[-areacluster].frontcluster != cluster; - return aasworld.portals[-areacluster].clusterareanum[side]; - } //end else -} //end of the function AAS_ClusterAreaNum -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_InitTravelFlagFromType(void) -{ - int i; - - for (i = 0; i < MAX_TRAVELTYPES; i++) - { - aasworld.travelflagfortype[i] = TFL_INVALID; - } //end for - aasworld.travelflagfortype[TRAVEL_INVALID] = TFL_INVALID; - aasworld.travelflagfortype[TRAVEL_WALK] = TFL_WALK; - aasworld.travelflagfortype[TRAVEL_CROUCH] = TFL_CROUCH; - aasworld.travelflagfortype[TRAVEL_BARRIERJUMP] = TFL_BARRIERJUMP; - aasworld.travelflagfortype[TRAVEL_JUMP] = TFL_JUMP; - aasworld.travelflagfortype[TRAVEL_LADDER] = TFL_LADDER; - aasworld.travelflagfortype[TRAVEL_WALKOFFLEDGE] = TFL_WALKOFFLEDGE; - aasworld.travelflagfortype[TRAVEL_SWIM] = TFL_SWIM; - aasworld.travelflagfortype[TRAVEL_WATERJUMP] = TFL_WATERJUMP; - aasworld.travelflagfortype[TRAVEL_TELEPORT] = TFL_TELEPORT; - aasworld.travelflagfortype[TRAVEL_ELEVATOR] = TFL_ELEVATOR; - aasworld.travelflagfortype[TRAVEL_ROCKETJUMP] = TFL_ROCKETJUMP; - aasworld.travelflagfortype[TRAVEL_BFGJUMP] = TFL_BFGJUMP; - aasworld.travelflagfortype[TRAVEL_GRAPPLEHOOK] = TFL_GRAPPLEHOOK; - aasworld.travelflagfortype[TRAVEL_DOUBLEJUMP] = TFL_DOUBLEJUMP; - aasworld.travelflagfortype[TRAVEL_RAMPJUMP] = TFL_RAMPJUMP; - aasworld.travelflagfortype[TRAVEL_STRAFEJUMP] = TFL_STRAFEJUMP; - aasworld.travelflagfortype[TRAVEL_JUMPPAD] = TFL_JUMPPAD; - aasworld.travelflagfortype[TRAVEL_FUNCBOB] = TFL_FUNCBOB; -} //end of the function AAS_InitTravelFlagFromType -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -ID_INLINE int AAS_TravelFlagForType_inline(int traveltype) -{ - int tfl; - - tfl = 0; - if (tfl & TRAVELFLAG_NOTTEAM1) - tfl |= TFL_NOTTEAM1; - if (tfl & TRAVELFLAG_NOTTEAM2) - tfl |= TFL_NOTTEAM2; - traveltype &= TRAVELTYPE_MASK; - if (traveltype < 0 || traveltype >= MAX_TRAVELTYPES) - return TFL_INVALID; - tfl |= aasworld.travelflagfortype[traveltype]; - return tfl; -} //end of the function AAS_TravelFlagForType_inline -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_TravelFlagForType(int traveltype) -{ - return AAS_TravelFlagForType_inline(traveltype); -} //end of the function AAS_TravelFlagForType_inline -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_UnlinkCache(aas_routingcache_t *cache) -{ - if (cache->time_next) cache->time_next->time_prev = cache->time_prev; - else aasworld.newestcache = cache->time_prev; - if (cache->time_prev) cache->time_prev->time_next = cache->time_next; - else aasworld.oldestcache = cache->time_next; - cache->time_next = NULL; - cache->time_prev = NULL; -} //end of the function AAS_UnlinkCache -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_LinkCache(aas_routingcache_t *cache) -{ - if (aasworld.newestcache) - { - aasworld.newestcache->time_next = cache; - cache->time_prev = aasworld.newestcache; - } //end if - else - { - aasworld.oldestcache = cache; - cache->time_prev = NULL; - } //end else - cache->time_next = NULL; - aasworld.newestcache = cache; -} //end of the function AAS_LinkCache -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_FreeRoutingCache(aas_routingcache_t *cache) -{ - AAS_UnlinkCache(cache); - routingcachesize -= cache->size; - FreeMemory(cache); -} //end of the function AAS_FreeRoutingCache -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_RemoveRoutingCacheInCluster( int clusternum ) -{ - int i; - aas_routingcache_t *cache, *nextcache; - aas_cluster_t *cluster; - - if (!aasworld.clusterareacache) - return; - cluster = &aasworld.clusters[clusternum]; - for (i = 0; i < cluster->numareas; i++) - { - for (cache = aasworld.clusterareacache[clusternum][i]; cache; cache = nextcache) - { - nextcache = cache->next; - AAS_FreeRoutingCache(cache); - } //end for - aasworld.clusterareacache[clusternum][i] = NULL; - } //end for -} //end of the function AAS_RemoveRoutingCacheInCluster -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_RemoveRoutingCacheUsingArea( int areanum ) -{ - int i, clusternum; - aas_routingcache_t *cache, *nextcache; - - clusternum = aasworld.areasettings[areanum].cluster; - if (clusternum > 0) - { - //remove all the cache in the cluster the area is in - AAS_RemoveRoutingCacheInCluster( clusternum ); - } //end if - else - { - // if this is a portal remove all cache in both the front and back cluster - AAS_RemoveRoutingCacheInCluster( aasworld.portals[-clusternum].frontcluster ); - AAS_RemoveRoutingCacheInCluster( aasworld.portals[-clusternum].backcluster ); - } //end else - // remove all portal cache - for (i = 0; i < aasworld.numareas; i++) - { - //refresh portal cache - for (cache = aasworld.portalcache[i]; cache; cache = nextcache) - { - nextcache = cache->next; - AAS_FreeRoutingCache(cache); - } //end for - aasworld.portalcache[i] = NULL; - } //end for -} //end of the function AAS_RemoveRoutingCacheUsingArea -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_EnableRoutingArea(int areanum, int enable) -{ - int flags; - - if (areanum <= 0 || areanum >= aasworld.numareas) - { - if (bot_developer) - { - botimport.Print(PRT_ERROR, "AAS_EnableRoutingArea: areanum %d out of range\n", areanum); - } //end if - return 0; - } //end if - flags = aasworld.areasettings[areanum].areaflags & AREA_DISABLED; - if (enable < 0) - return !flags; - - if (enable) - aasworld.areasettings[areanum].areaflags &= ~AREA_DISABLED; - else - aasworld.areasettings[areanum].areaflags |= AREA_DISABLED; - // if the status of the area changed - if ( (flags & AREA_DISABLED) != (aasworld.areasettings[areanum].areaflags & AREA_DISABLED) ) - { - //remove all routing cache involving this area - AAS_RemoveRoutingCacheUsingArea( areanum ); - } //end if - return !flags; -} //end of the function AAS_EnableRoutingArea -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -ID_INLINE float AAS_RoutingTime(void) -{ - return AAS_Time(); -} //end of the function AAS_RoutingTime -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_GetAreaContentsTravelFlags(int areanum) -{ - int contents, tfl; - - contents = aasworld.areasettings[areanum].contents; - tfl = 0; - if (contents & AREACONTENTS_WATER) - tfl |= TFL_WATER; - else if (contents & AREACONTENTS_SLIME) - tfl |= TFL_SLIME; - else if (contents & AREACONTENTS_LAVA) - tfl |= TFL_LAVA; - else - tfl |= TFL_AIR; - if (contents & AREACONTENTS_DONOTENTER) - tfl |= TFL_DONOTENTER; - if (contents & AREACONTENTS_NOTTEAM1) - tfl |= TFL_NOTTEAM1; - if (contents & AREACONTENTS_NOTTEAM2) - tfl |= TFL_NOTTEAM2; - if (aasworld.areasettings[areanum].areaflags & AREA_BRIDGE) - tfl |= TFL_BRIDGE; - return tfl; -} //end of the function AAS_GetAreaContentsTravelFlags -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -ID_INLINE int AAS_AreaContentsTravelFlags_inline(int areanum) -{ - return aasworld.areacontentstravelflags[areanum]; -} //end of the function AAS_AreaContentsTravelFlags -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_AreaContentsTravelFlags(int areanum) -{ - return aasworld.areacontentstravelflags[areanum]; -} //end of the function AAS_AreaContentsTravelFlags -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_InitAreaContentsTravelFlags(void) -{ - int i; - - if (aasworld.areacontentstravelflags) FreeMemory(aasworld.areacontentstravelflags); - aasworld.areacontentstravelflags = (int *) GetClearedMemory(aasworld.numareas * sizeof(int)); - // - for (i = 0; i < aasworld.numareas; i++) { - aasworld.areacontentstravelflags[i] = AAS_GetAreaContentsTravelFlags(i); - } -} //end of the function AAS_InitAreaContentsTravelFlags -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_CreateReversedReachability(void) -{ - int i, n; - aas_reversedlink_t *revlink; - aas_reachability_t *reach; - aas_areasettings_t *settings; - char *ptr; -#ifdef DEBUG - int starttime; - - starttime = Sys_MilliSeconds(); -#endif - //free reversed links that have already been created - if (aasworld.reversedreachability) FreeMemory(aasworld.reversedreachability); - //allocate memory for the reversed reachability links - ptr = (char *) GetClearedMemory(aasworld.numareas * sizeof(aas_reversedreachability_t) + - aasworld.reachabilitysize * sizeof(aas_reversedlink_t)); - // - aasworld.reversedreachability = (aas_reversedreachability_t *) ptr; - //pointer to the memory for the reversed links - ptr += aasworld.numareas * sizeof(aas_reversedreachability_t); - //check all reachabilities of all areas - for (i = 1; i < aasworld.numareas; i++) - { - //settings of the area - settings = &aasworld.areasettings[i]; - // - if (settings->numreachableareas >= 128) - botimport.Print(PRT_WARNING, "area %d has more than 128 reachabilities\n", i); - //create reversed links for the reachabilities - for (n = 0; n < settings->numreachableareas && n < 128; n++) - { - //reachability link - reach = &aasworld.reachability[settings->firstreachablearea + n]; - // - revlink = (aas_reversedlink_t *) ptr; - ptr += sizeof(aas_reversedlink_t); - // - revlink->areanum = i; - revlink->linknum = settings->firstreachablearea + n; - revlink->next = aasworld.reversedreachability[reach->areanum].first; - aasworld.reversedreachability[reach->areanum].first = revlink; - aasworld.reversedreachability[reach->areanum].numlinks++; - } //end for - } //end for -#ifdef DEBUG - botimport.Print(PRT_MESSAGE, "reversed reachability %d msec\n", Sys_MilliSeconds() - starttime); -#endif -} //end of the function AAS_CreateReversedReachability -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -unsigned short int AAS_AreaTravelTime(int areanum, vec3_t start, vec3_t end) -{ - int intdist; - float dist; - vec3_t dir; - - VectorSubtract(start, end, dir); - dist = VectorLength(dir); - //if crouch only area - if (AAS_AreaCrouch(areanum)) dist *= DISTANCEFACTOR_CROUCH; - //if swim area - else if (AAS_AreaSwim(areanum)) dist *= DISTANCEFACTOR_SWIM; - //normal walk area - else dist *= DISTANCEFACTOR_WALK; - // - intdist = (int) dist; - //make sure the distance isn't zero - if (intdist <= 0) intdist = 1; - return intdist; -} //end of the function AAS_AreaTravelTime -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_CalculateAreaTravelTimes(void) -{ - int i, l, n, size; - char *ptr; - vec3_t end; - aas_reversedreachability_t *revreach; - aas_reversedlink_t *revlink; - aas_reachability_t *reach; - aas_areasettings_t *settings; - int starttime; - - starttime = Sys_MilliSeconds(); - //if there are still area travel times, free the memory - if (aasworld.areatraveltimes) FreeMemory(aasworld.areatraveltimes); - //get the total size of all the area travel times - size = aasworld.numareas * sizeof(unsigned short **); - for (i = 0; i < aasworld.numareas; i++) - { - revreach = &aasworld.reversedreachability[i]; - //settings of the area - settings = &aasworld.areasettings[i]; - // - size += settings->numreachableareas * sizeof(unsigned short *); - // - size += settings->numreachableareas * - PAD(revreach->numlinks, sizeof(long)) * sizeof(unsigned short); - } //end for - //allocate memory for the area travel times - ptr = (char *) GetClearedMemory(size); - aasworld.areatraveltimes = (unsigned short ***) ptr; - ptr += aasworld.numareas * sizeof(unsigned short **); - //calcluate the travel times for all the areas - for (i = 0; i < aasworld.numareas; i++) - { - //reversed reachabilities of this area - revreach = &aasworld.reversedreachability[i]; - //settings of the area - settings = &aasworld.areasettings[i]; - // - aasworld.areatraveltimes[i] = (unsigned short **) ptr; - ptr += settings->numreachableareas * sizeof(unsigned short *); - // - for (l = 0; l < settings->numreachableareas; l++) - { - aasworld.areatraveltimes[i][l] = (unsigned short *) ptr; - ptr += PAD(revreach->numlinks, sizeof(long)) * sizeof(unsigned short); - //reachability link - reach = &aasworld.reachability[settings->firstreachablearea + l]; - // - for (n = 0, revlink = revreach->first; revlink; revlink = revlink->next, n++) - { - VectorCopy(aasworld.reachability[revlink->linknum].end, end); - // - aasworld.areatraveltimes[i][l][n] = AAS_AreaTravelTime(i, end, reach->start); - } //end for - } //end for - } //end for -#ifdef DEBUG - botimport.Print(PRT_MESSAGE, "area travel times %d msec\n", Sys_MilliSeconds() - starttime); -#endif -} //end of the function AAS_CalculateAreaTravelTimes -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_PortalMaxTravelTime(int portalnum) -{ - int l, n, t, maxt; - aas_portal_t *portal; - aas_reversedreachability_t *revreach; - aas_reversedlink_t *revlink; - aas_areasettings_t *settings; - - portal = &aasworld.portals[portalnum]; - //reversed reachabilities of this portal area - revreach = &aasworld.reversedreachability[portal->areanum]; - //settings of the portal area - settings = &aasworld.areasettings[portal->areanum]; - // - maxt = 0; - for (l = 0; l < settings->numreachableareas; l++) - { - for (n = 0, revlink = revreach->first; revlink; revlink = revlink->next, n++) - { - t = aasworld.areatraveltimes[portal->areanum][l][n]; - if (t > maxt) - { - maxt = t; - } //end if - } //end for - } //end for - return maxt; -} //end of the function AAS_PortalMaxTravelTime -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_InitPortalMaxTravelTimes(void) -{ - int i; - - if (aasworld.portalmaxtraveltimes) FreeMemory(aasworld.portalmaxtraveltimes); - - aasworld.portalmaxtraveltimes = (int *) GetClearedMemory(aasworld.numportals * sizeof(int)); - - for (i = 0; i < aasworld.numportals; i++) - { - aasworld.portalmaxtraveltimes[i] = AAS_PortalMaxTravelTime(i); - //botimport.Print(PRT_MESSAGE, "portal %d max tt = %d\n", i, aasworld.portalmaxtraveltimes[i]); - } //end for -} //end of the function AAS_InitPortalMaxTravelTimes -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -/* -int AAS_FreeOldestCache(void) -{ - int i, j, bestcluster, bestarea, freed; - float besttime; - aas_routingcache_t *cache, *bestcache; - - freed = qfalse; - besttime = 999999999; - bestcache = NULL; - bestcluster = 0; - bestarea = 0; - //refresh cluster cache - for (i = 0; i < aasworld.numclusters; i++) - { - for (j = 0; j < aasworld.clusters[i].numareas; j++) - { - for (cache = aasworld.clusterareacache[i][j]; cache; cache = cache->next) - { - //never remove cache leading towards a portal - if (aasworld.areasettings[cache->areanum].cluster < 0) continue; - //if this cache is older than the cache we found so far - if (cache->time < besttime) - { - bestcache = cache; - bestcluster = i; - bestarea = j; - besttime = cache->time; - } //end if - } //end for - } //end for - } //end for - if (bestcache) - { - cache = bestcache; - if (cache->prev) cache->prev->next = cache->next; - else aasworld.clusterareacache[bestcluster][bestarea] = cache->next; - if (cache->next) cache->next->prev = cache->prev; - AAS_FreeRoutingCache(cache); - freed = qtrue; - } //end if - besttime = 999999999; - bestcache = NULL; - bestarea = 0; - for (i = 0; i < aasworld.numareas; i++) - { - //refresh portal cache - for (cache = aasworld.portalcache[i]; cache; cache = cache->next) - { - if (cache->time < besttime) - { - bestcache = cache; - bestarea = i; - besttime = cache->time; - } //end if - } //end for - } //end for - if (bestcache) - { - cache = bestcache; - if (cache->prev) cache->prev->next = cache->next; - else aasworld.portalcache[bestarea] = cache->next; - if (cache->next) cache->next->prev = cache->prev; - AAS_FreeRoutingCache(cache); - freed = qtrue; - } //end if - return freed; -} //end of the function AAS_FreeOldestCache -*/ -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_FreeOldestCache(void) -{ - int clusterareanum; - aas_routingcache_t *cache; - - for (cache = aasworld.oldestcache; cache; cache = cache->time_next) { - // never free area cache leading towards a portal - if (cache->type == CACHETYPE_AREA && aasworld.areasettings[cache->areanum].cluster < 0) { - continue; - } - break; - } - if (cache) { - // unlink the cache - if (cache->type == CACHETYPE_AREA) { - //number of the area in the cluster - clusterareanum = AAS_ClusterAreaNum(cache->cluster, cache->areanum); - // unlink from cluster area cache - if (cache->prev) cache->prev->next = cache->next; - else aasworld.clusterareacache[cache->cluster][clusterareanum] = cache->next; - if (cache->next) cache->next->prev = cache->prev; - } - else { - // unlink from portal cache - if (cache->prev) cache->prev->next = cache->next; - else aasworld.portalcache[cache->areanum] = cache->next; - if (cache->next) cache->next->prev = cache->prev; - } - AAS_FreeRoutingCache(cache); - return qtrue; - } - return qfalse; -} //end of the function AAS_FreeOldestCache -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -aas_routingcache_t *AAS_AllocRoutingCache(int numtraveltimes) -{ - aas_routingcache_t *cache; - int size; - - // - size = sizeof(aas_routingcache_t) - + numtraveltimes * sizeof(unsigned short int) - + numtraveltimes * sizeof(unsigned char); - // - routingcachesize += size; - // - cache = (aas_routingcache_t *) GetClearedMemory(size); - cache->reachabilities = (unsigned char *) cache + sizeof(aas_routingcache_t) - + numtraveltimes * sizeof(unsigned short int); - cache->size = size; - return cache; -} //end of the function AAS_AllocRoutingCache -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_FreeAllClusterAreaCache(void) -{ - int i, j; - aas_routingcache_t *cache, *nextcache; - aas_cluster_t *cluster; - - //free all cluster cache if existing - if (!aasworld.clusterareacache) return; - //free caches - for (i = 0; i < aasworld.numclusters; i++) - { - cluster = &aasworld.clusters[i]; - for (j = 0; j < cluster->numareas; j++) - { - for (cache = aasworld.clusterareacache[i][j]; cache; cache = nextcache) - { - nextcache = cache->next; - AAS_FreeRoutingCache(cache); - } //end for - aasworld.clusterareacache[i][j] = NULL; - } //end for - } //end for - //free the cluster cache array - FreeMemory(aasworld.clusterareacache); - aasworld.clusterareacache = NULL; -} //end of the function AAS_FreeAllClusterAreaCache -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_InitClusterAreaCache(void) -{ - int i, size; - char *ptr; - - // - for (size = 0, i = 0; i < aasworld.numclusters; i++) - { - size += aasworld.clusters[i].numareas; - } //end for - //two dimensional array with pointers for every cluster to routing cache - //for every area in that cluster - ptr = (char *) GetClearedMemory( - aasworld.numclusters * sizeof(aas_routingcache_t **) + - size * sizeof(aas_routingcache_t *)); - aasworld.clusterareacache = (aas_routingcache_t ***) ptr; - ptr += aasworld.numclusters * sizeof(aas_routingcache_t **); - for (i = 0; i < aasworld.numclusters; i++) - { - aasworld.clusterareacache[i] = (aas_routingcache_t **) ptr; - ptr += aasworld.clusters[i].numareas * sizeof(aas_routingcache_t *); - } //end for -} //end of the function AAS_InitClusterAreaCache -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_FreeAllPortalCache(void) -{ - int i; - aas_routingcache_t *cache, *nextcache; - - //free all portal cache if existing - if (!aasworld.portalcache) return; - //free portal caches - for (i = 0; i < aasworld.numareas; i++) - { - for (cache = aasworld.portalcache[i]; cache; cache = nextcache) - { - nextcache = cache->next; - AAS_FreeRoutingCache(cache); - } //end for - aasworld.portalcache[i] = NULL; - } //end for - FreeMemory(aasworld.portalcache); - aasworld.portalcache = NULL; -} //end of the function AAS_FreeAllPortalCache -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_InitPortalCache(void) -{ - // - aasworld.portalcache = (aas_routingcache_t **) GetClearedMemory( - aasworld.numareas * sizeof(aas_routingcache_t *)); -} //end of the function AAS_InitPortalCache -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_InitRoutingUpdate(void) -{ - int i, maxreachabilityareas; - - //free routing update fields if already existing - if (aasworld.areaupdate) FreeMemory(aasworld.areaupdate); - // - maxreachabilityareas = 0; - for (i = 0; i < aasworld.numclusters; i++) - { - if (aasworld.clusters[i].numreachabilityareas > maxreachabilityareas) - { - maxreachabilityareas = aasworld.clusters[i].numreachabilityareas; - } //end if - } //end for - //allocate memory for the routing update fields - aasworld.areaupdate = (aas_routingupdate_t *) GetClearedMemory( - maxreachabilityareas * sizeof(aas_routingupdate_t)); - // - if (aasworld.portalupdate) FreeMemory(aasworld.portalupdate); - //allocate memory for the portal update fields - aasworld.portalupdate = (aas_routingupdate_t *) GetClearedMemory( - (aasworld.numportals+1) * sizeof(aas_routingupdate_t)); -} //end of the function AAS_InitRoutingUpdate -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_CreateAllRoutingCache(void) -{ - int i, j, t; - - aasworld.initialized = qtrue; - botimport.Print(PRT_MESSAGE, "AAS_CreateAllRoutingCache\n"); - for (i = 1; i < aasworld.numareas; i++) - { - if (!AAS_AreaReachability(i)) continue; - for (j = 1; j < aasworld.numareas; j++) - { - if (i == j) continue; - if (!AAS_AreaReachability(j)) continue; - t = AAS_AreaTravelTimeToGoalArea(i, aasworld.areas[i].center, j, TFL_DEFAULT); - //Log_Write("traveltime from %d to %d is %d", i, j, t); - } //end for - } //end for - aasworld.initialized = qfalse; -} //end of the function AAS_CreateAllRoutingCache -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== - -//the route cache header -//this header is followed by numportalcache + numareacache aas_routingcache_t -//structures that store routing cache -typedef struct routecacheheader_s -{ - int ident; - int version; - int numareas; - int numclusters; - int areacrc; - int clustercrc; - int numportalcache; - int numareacache; -} routecacheheader_t; - -#define RCID (('C'<<24)+('R'<<16)+('E'<<8)+'M') -#define RCVERSION 2 - -//void AAS_DecompressVis(byte *in, int numareas, byte *decompressed); -//int AAS_CompressVis(byte *vis, int numareas, byte *dest); - -void AAS_WriteRouteCache(void) -{ - int i, j, numportalcache, numareacache, totalsize; - aas_routingcache_t *cache; - aas_cluster_t *cluster; - fileHandle_t fp; - char filename[MAX_QPATH]; - routecacheheader_t routecacheheader; - - numportalcache = 0; - for (i = 0; i < aasworld.numareas; i++) - { - for (cache = aasworld.portalcache[i]; cache; cache = cache->next) - { - numportalcache++; - } //end for - } //end for - numareacache = 0; - for (i = 0; i < aasworld.numclusters; i++) - { - cluster = &aasworld.clusters[i]; - for (j = 0; j < cluster->numareas; j++) - { - for (cache = aasworld.clusterareacache[i][j]; cache; cache = cache->next) - { - numareacache++; - } //end for - } //end for - } //end for - // open the file for writing - Com_sprintf(filename, MAX_QPATH, "maps/%s.rcd", aasworld.mapname); - botimport.FS_FOpenFile( filename, &fp, FS_WRITE ); - if (!fp) - { - AAS_Error("Unable to open file: %s\n", filename); - return; - } //end if - //create the header - routecacheheader.ident = RCID; - routecacheheader.version = RCVERSION; - routecacheheader.numareas = aasworld.numareas; - routecacheheader.numclusters = aasworld.numclusters; - routecacheheader.areacrc = CRC_ProcessString( (unsigned char *)aasworld.areas, sizeof(aas_area_t) * aasworld.numareas ); - routecacheheader.clustercrc = CRC_ProcessString( (unsigned char *)aasworld.clusters, sizeof(aas_cluster_t) * aasworld.numclusters ); - routecacheheader.numportalcache = numportalcache; - routecacheheader.numareacache = numareacache; - //write the header - botimport.FS_Write(&routecacheheader, sizeof(routecacheheader_t), fp); - // - totalsize = 0; - //write all the cache - for (i = 0; i < aasworld.numareas; i++) - { - for (cache = aasworld.portalcache[i]; cache; cache = cache->next) - { - botimport.FS_Write(cache, cache->size, fp); - totalsize += cache->size; - } //end for - } //end for - for (i = 0; i < aasworld.numclusters; i++) - { - cluster = &aasworld.clusters[i]; - for (j = 0; j < cluster->numareas; j++) - { - for (cache = aasworld.clusterareacache[i][j]; cache; cache = cache->next) - { - botimport.FS_Write(cache, cache->size, fp); - totalsize += cache->size; - } //end for - } //end for - } //end for - // write the visareas - /* - for (i = 0; i < aasworld.numareas; i++) - { - if (!aasworld.areavisibility[i]) { - size = 0; - botimport.FS_Write(&size, sizeof(int), fp); - continue; - } - AAS_DecompressVis( aasworld.areavisibility[i], aasworld.numareas, aasworld.decompressedvis ); - size = AAS_CompressVis( aasworld.decompressedvis, aasworld.numareas, aasworld.decompressedvis ); - botimport.FS_Write(&size, sizeof(int), fp); - botimport.FS_Write(aasworld.decompressedvis, size, fp); - } - */ - // - botimport.FS_FCloseFile(fp); - botimport.Print(PRT_MESSAGE, "\nroute cache written to %s\n", filename); - botimport.Print(PRT_MESSAGE, "written %d bytes of routing cache\n", totalsize); -} //end of the function AAS_WriteRouteCache -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -aas_routingcache_t *AAS_ReadCache(fileHandle_t fp) -{ - int size; - aas_routingcache_t *cache; - - botimport.FS_Read(&size, sizeof(size), fp); - cache = (aas_routingcache_t *) GetMemory(size); - cache->size = size; - botimport.FS_Read((unsigned char *)cache + sizeof(size), size - sizeof(size), fp); - cache->reachabilities = (unsigned char *) cache + sizeof(aas_routingcache_t) - sizeof(unsigned short) + - (size - sizeof(aas_routingcache_t) + sizeof(unsigned short)) / 3 * 2; - return cache; -} //end of the function AAS_ReadCache -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_ReadRouteCache(void) -{ - int i, clusterareanum;//, size; - fileHandle_t fp; - char filename[MAX_QPATH]; - routecacheheader_t routecacheheader; - aas_routingcache_t *cache; - - Com_sprintf(filename, MAX_QPATH, "maps/%s.rcd", aasworld.mapname); - botimport.FS_FOpenFile( filename, &fp, FS_READ ); - if (!fp) - { - return qfalse; - } //end if - botimport.FS_Read(&routecacheheader, sizeof(routecacheheader_t), fp ); - if (routecacheheader.ident != RCID) - { - AAS_Error("%s is not a route cache dump\n"); - return qfalse; - } //end if - if (routecacheheader.version != RCVERSION) - { - AAS_Error("route cache dump has wrong version %d, should be %d", routecacheheader.version, RCVERSION); - return qfalse; - } //end if - if (routecacheheader.numareas != aasworld.numareas) - { - //AAS_Error("route cache dump has wrong number of areas\n"); - return qfalse; - } //end if - if (routecacheheader.numclusters != aasworld.numclusters) - { - //AAS_Error("route cache dump has wrong number of clusters\n"); - return qfalse; - } //end if - if (routecacheheader.areacrc != - CRC_ProcessString( (unsigned char *)aasworld.areas, sizeof(aas_area_t) * aasworld.numareas )) - { - //AAS_Error("route cache dump area CRC incorrect\n"); - return qfalse; - } //end if - if (routecacheheader.clustercrc != - CRC_ProcessString( (unsigned char *)aasworld.clusters, sizeof(aas_cluster_t) * aasworld.numclusters )) - { - //AAS_Error("route cache dump cluster CRC incorrect\n"); - return qfalse; - } //end if - //read all the portal cache - for (i = 0; i < routecacheheader.numportalcache; i++) - { - cache = AAS_ReadCache(fp); - cache->next = aasworld.portalcache[cache->areanum]; - cache->prev = NULL; - if (aasworld.portalcache[cache->areanum]) - aasworld.portalcache[cache->areanum]->prev = cache; - aasworld.portalcache[cache->areanum] = cache; - } //end for - //read all the cluster area cache - for (i = 0; i < routecacheheader.numareacache; i++) - { - cache = AAS_ReadCache(fp); - clusterareanum = AAS_ClusterAreaNum(cache->cluster, cache->areanum); - cache->next = aasworld.clusterareacache[cache->cluster][clusterareanum]; - cache->prev = NULL; - if (aasworld.clusterareacache[cache->cluster][clusterareanum]) - aasworld.clusterareacache[cache->cluster][clusterareanum]->prev = cache; - aasworld.clusterareacache[cache->cluster][clusterareanum] = cache; - } //end for - // read the visareas - /* - aasworld.areavisibility = (byte **) GetClearedMemory(aasworld.numareas * sizeof(byte *)); - aasworld.decompressedvis = (byte *) GetClearedMemory(aasworld.numareas * sizeof(byte)); - for (i = 0; i < aasworld.numareas; i++) - { - botimport.FS_Read(&size, sizeof(size), fp ); - if (size) { - aasworld.areavisibility[i] = (byte *) GetMemory(size); - botimport.FS_Read(aasworld.areavisibility[i], size, fp ); - } - } - */ - // - botimport.FS_FCloseFile(fp); - return qtrue; -} //end of the function AAS_ReadRouteCache -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -#define MAX_REACHABILITYPASSAREAS 32 - -void AAS_InitReachabilityAreas(void) -{ - int i, j, numareas, areas[MAX_REACHABILITYPASSAREAS]; - int numreachareas; - aas_reachability_t *reach; - vec3_t start, end; - - if (aasworld.reachabilityareas) - FreeMemory(aasworld.reachabilityareas); - if (aasworld.reachabilityareaindex) - FreeMemory(aasworld.reachabilityareaindex); - - aasworld.reachabilityareas = (aas_reachabilityareas_t *) - GetClearedMemory(aasworld.reachabilitysize * sizeof(aas_reachabilityareas_t)); - aasworld.reachabilityareaindex = (int *) - GetClearedMemory(aasworld.reachabilitysize * MAX_REACHABILITYPASSAREAS * sizeof(int)); - numreachareas = 0; - for (i = 0; i < aasworld.reachabilitysize; i++) - { - reach = &aasworld.reachability[i]; - numareas = 0; - switch(reach->traveltype & TRAVELTYPE_MASK) - { - //trace areas from start to end - case TRAVEL_BARRIERJUMP: - case TRAVEL_WATERJUMP: - VectorCopy(reach->start, end); - end[2] = reach->end[2]; - numareas = AAS_TraceAreas(reach->start, end, areas, NULL, MAX_REACHABILITYPASSAREAS); - break; - case TRAVEL_WALKOFFLEDGE: - VectorCopy(reach->end, start); - start[2] = reach->start[2]; - numareas = AAS_TraceAreas(start, reach->end, areas, NULL, MAX_REACHABILITYPASSAREAS); - break; - case TRAVEL_GRAPPLEHOOK: - numareas = AAS_TraceAreas(reach->start, reach->end, areas, NULL, MAX_REACHABILITYPASSAREAS); - break; - - //trace arch - case TRAVEL_JUMP: break; - case TRAVEL_ROCKETJUMP: break; - case TRAVEL_BFGJUMP: break; - case TRAVEL_JUMPPAD: break; - - //trace from reach->start to entity center, along entity movement - //and from entity center to reach->end - case TRAVEL_ELEVATOR: break; - case TRAVEL_FUNCBOB: break; - - //no areas in between - case TRAVEL_WALK: break; - case TRAVEL_CROUCH: break; - case TRAVEL_LADDER: break; - case TRAVEL_SWIM: break; - case TRAVEL_TELEPORT: break; - default: break; - } //end switch - aasworld.reachabilityareas[i].firstarea = numreachareas; - aasworld.reachabilityareas[i].numareas = numareas; - for (j = 0; j < numareas; j++) - { - aasworld.reachabilityareaindex[numreachareas++] = areas[j]; - } //end for - } //end for -} //end of the function AAS_InitReachabilityAreas -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_InitRouting(void) -{ - AAS_InitTravelFlagFromType(); - // - AAS_InitAreaContentsTravelFlags(); - //initialize the routing update fields - AAS_InitRoutingUpdate(); - //create reversed reachability links used by the routing update algorithm - AAS_CreateReversedReachability(); - //initialize the cluster cache - AAS_InitClusterAreaCache(); - //initialize portal cache - AAS_InitPortalCache(); - //initialize the area travel times - AAS_CalculateAreaTravelTimes(); - //calculate the maximum travel times through portals - AAS_InitPortalMaxTravelTimes(); - //get the areas reachabilities go through - AAS_InitReachabilityAreas(); - // -#ifdef ROUTING_DEBUG - numareacacheupdates = 0; - numportalcacheupdates = 0; -#endif //ROUTING_DEBUG - // - routingcachesize = 0; - max_routingcachesize = 1024 * (int) LibVarValue("max_routingcache", "4096"); - // read any routing cache if available - AAS_ReadRouteCache(); -} //end of the function AAS_InitRouting -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_FreeRoutingCaches(void) -{ - // free all the existing cluster area cache - AAS_FreeAllClusterAreaCache(); - // free all the existing portal cache - AAS_FreeAllPortalCache(); - // free cached travel times within areas - if (aasworld.areatraveltimes) FreeMemory(aasworld.areatraveltimes); - aasworld.areatraveltimes = NULL; - // free cached maximum travel time through cluster portals - if (aasworld.portalmaxtraveltimes) FreeMemory(aasworld.portalmaxtraveltimes); - aasworld.portalmaxtraveltimes = NULL; - // free reversed reachability links - if (aasworld.reversedreachability) FreeMemory(aasworld.reversedreachability); - aasworld.reversedreachability = NULL; - // free routing algorithm memory - if (aasworld.areaupdate) FreeMemory(aasworld.areaupdate); - aasworld.areaupdate = NULL; - if (aasworld.portalupdate) FreeMemory(aasworld.portalupdate); - aasworld.portalupdate = NULL; - // free lists with areas the reachabilities go through - if (aasworld.reachabilityareas) FreeMemory(aasworld.reachabilityareas); - aasworld.reachabilityareas = NULL; - // free the reachability area index - if (aasworld.reachabilityareaindex) FreeMemory(aasworld.reachabilityareaindex); - aasworld.reachabilityareaindex = NULL; - // free area contents travel flags look up table - if (aasworld.areacontentstravelflags) FreeMemory(aasworld.areacontentstravelflags); - aasworld.areacontentstravelflags = NULL; -} //end of the function AAS_FreeRoutingCaches -//=========================================================================== -// update the given routing cache -// -// Parameter: areacache : routing cache to update -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_UpdateAreaRoutingCache(aas_routingcache_t *areacache) -{ - int i, nextareanum, cluster, badtravelflags, clusterareanum, linknum; - int numreachabilityareas; - unsigned short int t, startareatraveltimes[128]; //NOTE: not more than 128 reachabilities per area allowed - aas_routingupdate_t *updateliststart, *updatelistend, *curupdate, *nextupdate; - aas_reachability_t *reach; - aas_reversedreachability_t *revreach; - aas_reversedlink_t *revlink; - -#ifdef ROUTING_DEBUG - numareacacheupdates++; -#endif //ROUTING_DEBUG - //number of reachability areas within this cluster - numreachabilityareas = aasworld.clusters[areacache->cluster].numreachabilityareas; - // - aasworld.frameroutingupdates++; - //clear the routing update fields -// Com_Memset(aasworld.areaupdate, 0, aasworld.numareas * sizeof(aas_routingupdate_t)); - // - badtravelflags = ~areacache->travelflags; - // - clusterareanum = AAS_ClusterAreaNum(areacache->cluster, areacache->areanum); - if (clusterareanum >= numreachabilityareas) return; - // - Com_Memset(startareatraveltimes, 0, sizeof(startareatraveltimes)); - // - curupdate = &aasworld.areaupdate[clusterareanum]; - curupdate->areanum = areacache->areanum; - //VectorCopy(areacache->origin, curupdate->start); - curupdate->areatraveltimes = startareatraveltimes; - curupdate->tmptraveltime = areacache->starttraveltime; - // - areacache->traveltimes[clusterareanum] = areacache->starttraveltime; - //put the area to start with in the current read list - curupdate->next = NULL; - curupdate->prev = NULL; - updateliststart = curupdate; - updatelistend = curupdate; - //while there are updates in the current list - while (updateliststart) - { - curupdate = updateliststart; - // - if (curupdate->next) curupdate->next->prev = NULL; - else updatelistend = NULL; - updateliststart = curupdate->next; - // - curupdate->inlist = qfalse; - //check all reversed reachability links - revreach = &aasworld.reversedreachability[curupdate->areanum]; - // - for (i = 0, revlink = revreach->first; revlink; revlink = revlink->next, i++) - { - linknum = revlink->linknum; - reach = &aasworld.reachability[linknum]; - //if there is used an undesired travel type - if (AAS_TravelFlagForType_inline(reach->traveltype) & badtravelflags) continue; - //if not allowed to enter the next area - if (aasworld.areasettings[reach->areanum].areaflags & AREA_DISABLED) continue; - //if the next area has a not allowed travel flag - if (AAS_AreaContentsTravelFlags_inline(reach->areanum) & badtravelflags) continue; - //number of the area the reversed reachability leads to - nextareanum = revlink->areanum; - //get the cluster number of the area - cluster = aasworld.areasettings[nextareanum].cluster; - //don't leave the cluster - if (cluster > 0 && cluster != areacache->cluster) continue; - //get the number of the area in the cluster - clusterareanum = AAS_ClusterAreaNum(areacache->cluster, nextareanum); - if (clusterareanum >= numreachabilityareas) continue; - //time already travelled plus the traveltime through - //the current area plus the travel time from the reachability - t = curupdate->tmptraveltime + - //AAS_AreaTravelTime(curupdate->areanum, curupdate->start, reach->end) + - curupdate->areatraveltimes[i] + - reach->traveltime; - // - if (!areacache->traveltimes[clusterareanum] || - areacache->traveltimes[clusterareanum] > t) - { - areacache->traveltimes[clusterareanum] = t; - areacache->reachabilities[clusterareanum] = linknum - aasworld.areasettings[nextareanum].firstreachablearea; - nextupdate = &aasworld.areaupdate[clusterareanum]; - nextupdate->areanum = nextareanum; - nextupdate->tmptraveltime = t; - //VectorCopy(reach->start, nextupdate->start); - nextupdate->areatraveltimes = aasworld.areatraveltimes[nextareanum][linknum - - aasworld.areasettings[nextareanum].firstreachablearea]; - if (!nextupdate->inlist) - { - // we add the update to the end of the list - // we could also use a B+ tree to have a real sorted list - // on travel time which makes for faster routing updates - nextupdate->next = NULL; - nextupdate->prev = updatelistend; - if (updatelistend) updatelistend->next = nextupdate; - else updateliststart = nextupdate; - updatelistend = nextupdate; - nextupdate->inlist = qtrue; - } //end if - } //end if - } //end for - } //end while -} //end of the function AAS_UpdateAreaRoutingCache -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -aas_routingcache_t *AAS_GetAreaRoutingCache(int clusternum, int areanum, int travelflags) -{ - int clusterareanum; - aas_routingcache_t *cache, *clustercache; - - //number of the area in the cluster - clusterareanum = AAS_ClusterAreaNum(clusternum, areanum); - //pointer to the cache for the area in the cluster - clustercache = aasworld.clusterareacache[clusternum][clusterareanum]; - //find the cache without undesired travel flags - for (cache = clustercache; cache; cache = cache->next) - { - //if there aren't used any undesired travel types for the cache - if (cache->travelflags == travelflags) break; - } //end for - //if there was no cache - if (!cache) - { - cache = AAS_AllocRoutingCache(aasworld.clusters[clusternum].numreachabilityareas); - cache->cluster = clusternum; - cache->areanum = areanum; - VectorCopy(aasworld.areas[areanum].center, cache->origin); - cache->starttraveltime = 1; - cache->travelflags = travelflags; - cache->prev = NULL; - cache->next = clustercache; - if (clustercache) clustercache->prev = cache; - aasworld.clusterareacache[clusternum][clusterareanum] = cache; - AAS_UpdateAreaRoutingCache(cache); - } //end if - else - { - AAS_UnlinkCache(cache); - } //end else - //the cache has been accessed - cache->time = AAS_RoutingTime(); - cache->type = CACHETYPE_AREA; - AAS_LinkCache(cache); - return cache; -} //end of the function AAS_GetAreaRoutingCache -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_UpdatePortalRoutingCache(aas_routingcache_t *portalcache) -{ - int i, portalnum, clusterareanum, clusternum; - unsigned short int t; - aas_portal_t *portal; - aas_cluster_t *cluster; - aas_routingcache_t *cache; - aas_routingupdate_t *updateliststart, *updatelistend, *curupdate, *nextupdate; - -#ifdef ROUTING_DEBUG - numportalcacheupdates++; -#endif //ROUTING_DEBUG - //clear the routing update fields -// Com_Memset(aasworld.portalupdate, 0, (aasworld.numportals+1) * sizeof(aas_routingupdate_t)); - // - curupdate = &aasworld.portalupdate[aasworld.numportals]; - curupdate->cluster = portalcache->cluster; - curupdate->areanum = portalcache->areanum; - curupdate->tmptraveltime = portalcache->starttraveltime; - //if the start area is a cluster portal, store the travel time for that portal - clusternum = aasworld.areasettings[portalcache->areanum].cluster; - if (clusternum < 0) - { - portalcache->traveltimes[-clusternum] = portalcache->starttraveltime; - } //end if - //put the area to start with in the current read list - curupdate->next = NULL; - curupdate->prev = NULL; - updateliststart = curupdate; - updatelistend = curupdate; - //while there are updates in the current list - while (updateliststart) - { - curupdate = updateliststart; - //remove the current update from the list - if (curupdate->next) curupdate->next->prev = NULL; - else updatelistend = NULL; - updateliststart = curupdate->next; - //current update is removed from the list - curupdate->inlist = qfalse; - // - cluster = &aasworld.clusters[curupdate->cluster]; - // - cache = AAS_GetAreaRoutingCache(curupdate->cluster, - curupdate->areanum, portalcache->travelflags); - //take all portals of the cluster - for (i = 0; i < cluster->numportals; i++) - { - portalnum = aasworld.portalindex[cluster->firstportal + i]; - portal = &aasworld.portals[portalnum]; - //if this is the portal of the current update continue - if (portal->areanum == curupdate->areanum) continue; - // - clusterareanum = AAS_ClusterAreaNum(curupdate->cluster, portal->areanum); - if (clusterareanum >= cluster->numreachabilityareas) continue; - // - t = cache->traveltimes[clusterareanum]; - if (!t) continue; - t += curupdate->tmptraveltime; - // - if (!portalcache->traveltimes[portalnum] || - portalcache->traveltimes[portalnum] > t) - { - portalcache->traveltimes[portalnum] = t; - nextupdate = &aasworld.portalupdate[portalnum]; - if (portal->frontcluster == curupdate->cluster) - { - nextupdate->cluster = portal->backcluster; - } //end if - else - { - nextupdate->cluster = portal->frontcluster; - } //end else - nextupdate->areanum = portal->areanum; - //add travel time through the actual portal area for the next update - nextupdate->tmptraveltime = t + aasworld.portalmaxtraveltimes[portalnum]; - if (!nextupdate->inlist) - { - // we add the update to the end of the list - // we could also use a B+ tree to have a real sorted list - // on travel time which makes for faster routing updates - nextupdate->next = NULL; - nextupdate->prev = updatelistend; - if (updatelistend) updatelistend->next = nextupdate; - else updateliststart = nextupdate; - updatelistend = nextupdate; - nextupdate->inlist = qtrue; - } //end if - } //end if - } //end for - } //end while -} //end of the function AAS_UpdatePortalRoutingCache -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -aas_routingcache_t *AAS_GetPortalRoutingCache(int clusternum, int areanum, int travelflags) -{ - aas_routingcache_t *cache; - - //find the cached portal routing if existing - for (cache = aasworld.portalcache[areanum]; cache; cache = cache->next) - { - if (cache->travelflags == travelflags) break; - } //end for - //if the portal routing isn't cached - if (!cache) - { - cache = AAS_AllocRoutingCache(aasworld.numportals); - cache->cluster = clusternum; - cache->areanum = areanum; - VectorCopy(aasworld.areas[areanum].center, cache->origin); - cache->starttraveltime = 1; - cache->travelflags = travelflags; - //add the cache to the cache list - cache->prev = NULL; - cache->next = aasworld.portalcache[areanum]; - if (aasworld.portalcache[areanum]) aasworld.portalcache[areanum]->prev = cache; - aasworld.portalcache[areanum] = cache; - //update the cache - AAS_UpdatePortalRoutingCache(cache); - } //end if - else - { - AAS_UnlinkCache(cache); - } //end else - //the cache has been accessed - cache->time = AAS_RoutingTime(); - cache->type = CACHETYPE_PORTAL; - AAS_LinkCache(cache); - return cache; -} //end of the function AAS_GetPortalRoutingCache -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_AreaRouteToGoalArea(int areanum, vec3_t origin, int goalareanum, int travelflags, int *traveltime, int *reachnum) -{ - int clusternum, goalclusternum, portalnum, i, clusterareanum, bestreachnum; - unsigned short int t, besttime; - aas_portal_t *portal; - aas_cluster_t *cluster; - aas_routingcache_t *areacache, *portalcache; - aas_reachability_t *reach; - - if (!aasworld.initialized) return qfalse; - - if (areanum == goalareanum) - { - *traveltime = 1; - *reachnum = 0; - return qtrue; - } - // - if (areanum <= 0 || areanum >= aasworld.numareas) - { - if (bot_developer) - { - botimport.Print(PRT_ERROR, "AAS_AreaTravelTimeToGoalArea: areanum %d out of range\n", areanum); - } //end if - return qfalse; - } //end if - if (goalareanum <= 0 || goalareanum >= aasworld.numareas) - { - if (bot_developer) - { - botimport.Print(PRT_ERROR, "AAS_AreaTravelTimeToGoalArea: goalareanum %d out of range\n", goalareanum); - } //end if - return qfalse; - } //end if - // make sure the routing cache doesn't grow to large - while(AvailableMemory() < 1 * 1024 * 1024) { - if (!AAS_FreeOldestCache()) break; - } - // - if (AAS_AreaDoNotEnter(areanum) || AAS_AreaDoNotEnter(goalareanum)) - { - travelflags |= TFL_DONOTENTER; - } //end if - //NOTE: the number of routing updates is limited per frame - /* - if (aasworld.frameroutingupdates > MAX_FRAMEROUTINGUPDATES) - { -#ifdef DEBUG - //Log_Write("WARNING: AAS_AreaTravelTimeToGoalArea: frame routing updates overflowed"); -#endif - return 0; - } //end if - */ - // - clusternum = aasworld.areasettings[areanum].cluster; - goalclusternum = aasworld.areasettings[goalareanum].cluster; - //check if the area is a portal of the goal area cluster - if (clusternum < 0 && goalclusternum > 0) - { - portal = &aasworld.portals[-clusternum]; - if (portal->frontcluster == goalclusternum || - portal->backcluster == goalclusternum) - { - clusternum = goalclusternum; - } //end if - } //end if - //check if the goalarea is a portal of the area cluster - else if (clusternum > 0 && goalclusternum < 0) - { - portal = &aasworld.portals[-goalclusternum]; - if (portal->frontcluster == clusternum || - portal->backcluster == clusternum) - { - goalclusternum = clusternum; - } //end if - } //end if - //if both areas are in the same cluster - //NOTE: there might be a shorter route via another cluster!!! but we don't care - if (clusternum > 0 && goalclusternum > 0 && clusternum == goalclusternum) - { - // - areacache = AAS_GetAreaRoutingCache(clusternum, goalareanum, travelflags); - //the number of the area in the cluster - clusterareanum = AAS_ClusterAreaNum(clusternum, areanum); - //the cluster the area is in - cluster = &aasworld.clusters[clusternum]; - //if the area is NOT a reachability area - if (clusterareanum >= cluster->numreachabilityareas) return 0; - //if it is possible to travel to the goal area through this cluster - if (areacache->traveltimes[clusterareanum] != 0) - { - *reachnum = aasworld.areasettings[areanum].firstreachablearea + - areacache->reachabilities[clusterareanum]; - if (!origin) { - *traveltime = areacache->traveltimes[clusterareanum]; - return qtrue; - } - reach = &aasworld.reachability[*reachnum]; - *traveltime = areacache->traveltimes[clusterareanum] + - AAS_AreaTravelTime(areanum, origin, reach->start); - // - return qtrue; - } //end if - } //end if - // - clusternum = aasworld.areasettings[areanum].cluster; - goalclusternum = aasworld.areasettings[goalareanum].cluster; - //if the goal area is a portal - if (goalclusternum < 0) - { - //just assume the goal area is part of the front cluster - portal = &aasworld.portals[-goalclusternum]; - goalclusternum = portal->frontcluster; - } //end if - //get the portal routing cache - portalcache = AAS_GetPortalRoutingCache(goalclusternum, goalareanum, travelflags); - //if the area is a cluster portal, read directly from the portal cache - if (clusternum < 0) - { - *traveltime = portalcache->traveltimes[-clusternum]; - *reachnum = aasworld.areasettings[areanum].firstreachablearea + - portalcache->reachabilities[-clusternum]; - return qtrue; - } //end if - // - besttime = 0; - bestreachnum = -1; - //the cluster the area is in - cluster = &aasworld.clusters[clusternum]; - //find the portal of the area cluster leading towards the goal area - for (i = 0; i < cluster->numportals; i++) - { - portalnum = aasworld.portalindex[cluster->firstportal + i]; - //if the goal area isn't reachable from the portal - if (!portalcache->traveltimes[portalnum]) continue; - // - portal = &aasworld.portals[portalnum]; - //get the cache of the portal area - areacache = AAS_GetAreaRoutingCache(clusternum, portal->areanum, travelflags); - //current area inside the current cluster - clusterareanum = AAS_ClusterAreaNum(clusternum, areanum); - //if the area is NOT a reachability area - if (clusterareanum >= cluster->numreachabilityareas) continue; - //if the portal is NOT reachable from this area - if (!areacache->traveltimes[clusterareanum]) continue; - //total travel time is the travel time the portal area is from - //the goal area plus the travel time towards the portal area - t = portalcache->traveltimes[portalnum] + areacache->traveltimes[clusterareanum]; - //FIXME: add the exact travel time through the actual portal area - //NOTE: for now we just add the largest travel time through the portal area - // because we can't directly calculate the exact travel time - // to be more specific we don't know which reachability was used to travel - // into the portal area - t += aasworld.portalmaxtraveltimes[portalnum]; - // - if (origin) - { - *reachnum = aasworld.areasettings[areanum].firstreachablearea + - areacache->reachabilities[clusterareanum]; - reach = aasworld.reachability + *reachnum; - t += AAS_AreaTravelTime(areanum, origin, reach->start); - } //end if - //if the time is better than the one already found - if (!besttime || t < besttime) - { - bestreachnum = *reachnum; - besttime = t; - } //end if - } //end for - if (bestreachnum < 0) { - return qfalse; - } - *reachnum = bestreachnum; - *traveltime = besttime; - return qtrue; -} //end of the function AAS_AreaRouteToGoalArea -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_AreaTravelTimeToGoalArea(int areanum, vec3_t origin, int goalareanum, int travelflags) -{ - int traveltime, reachnum; - - if (AAS_AreaRouteToGoalArea(areanum, origin, goalareanum, travelflags, &traveltime, &reachnum)) - { - return traveltime; - } - return 0; -} //end of the function AAS_AreaTravelTimeToGoalArea -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_AreaReachabilityToGoalArea(int areanum, vec3_t origin, int goalareanum, int travelflags) -{ - int traveltime, reachnum; - - if (AAS_AreaRouteToGoalArea(areanum, origin, goalareanum, travelflags, &traveltime, &reachnum)) - { - return reachnum; - } - return 0; -} //end of the function AAS_AreaReachabilityToGoalArea -//=========================================================================== -// predict the route and stop on one of the stop events -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_PredictRoute(struct aas_predictroute_s *route, int areanum, vec3_t origin, - int goalareanum, int travelflags, int maxareas, int maxtime, - int stopevent, int stopcontents, int stoptfl, int stopareanum) -{ - int curareanum, reachnum, i, j, testareanum; - vec3_t curorigin; - aas_reachability_t *reach; - aas_reachabilityareas_t *reachareas; - - //init output - route->stopevent = RSE_NONE; - route->endarea = goalareanum; - route->endcontents = 0; - route->endtravelflags = 0; - VectorCopy(origin, route->endpos); - route->time = 0; - - curareanum = areanum; - VectorCopy(origin, curorigin); - - for (i = 0; curareanum != goalareanum && (!maxareas || i < maxareas) && i < aasworld.numareas; i++) - { - reachnum = AAS_AreaReachabilityToGoalArea(curareanum, curorigin, goalareanum, travelflags); - if (!reachnum) - { - route->stopevent = RSE_NOROUTE; - return qfalse; - } //end if - reach = &aasworld.reachability[reachnum]; - // - if (stopevent & RSE_USETRAVELTYPE) - { - if (AAS_TravelFlagForType_inline(reach->traveltype) & stoptfl) - { - route->stopevent = RSE_USETRAVELTYPE; - route->endarea = curareanum; - route->endcontents = aasworld.areasettings[curareanum].contents; - route->endtravelflags = AAS_TravelFlagForType_inline(reach->traveltype); - VectorCopy(reach->start, route->endpos); - return qtrue; - } //end if - if (AAS_AreaContentsTravelFlags_inline(reach->areanum) & stoptfl) - { - route->stopevent = RSE_USETRAVELTYPE; - route->endarea = reach->areanum; - route->endcontents = aasworld.areasettings[reach->areanum].contents; - route->endtravelflags = AAS_AreaContentsTravelFlags_inline(reach->areanum); - VectorCopy(reach->end, route->endpos); - route->time += AAS_AreaTravelTime(areanum, origin, reach->start); - route->time += reach->traveltime; - return qtrue; - } //end if - } //end if - reachareas = &aasworld.reachabilityareas[reachnum]; - for (j = 0; j < reachareas->numareas + 1; j++) - { - if (j >= reachareas->numareas) - testareanum = reach->areanum; - else - testareanum = aasworld.reachabilityareaindex[reachareas->firstarea + j]; - if (stopevent & RSE_ENTERCONTENTS) - { - if (aasworld.areasettings[testareanum].contents & stopcontents) - { - route->stopevent = RSE_ENTERCONTENTS; - route->endarea = testareanum; - route->endcontents = aasworld.areasettings[testareanum].contents; - VectorCopy(reach->end, route->endpos); - route->time += AAS_AreaTravelTime(areanum, origin, reach->start); - route->time += reach->traveltime; - return qtrue; - } //end if - } //end if - if (stopevent & RSE_ENTERAREA) - { - if (testareanum == stopareanum) - { - route->stopevent = RSE_ENTERAREA; - route->endarea = testareanum; - route->endcontents = aasworld.areasettings[testareanum].contents; - VectorCopy(reach->start, route->endpos); - return qtrue; - } //end if - } //end if - } //end for - - route->time += AAS_AreaTravelTime(areanum, origin, reach->start); - route->time += reach->traveltime; - route->endarea = reach->areanum; - route->endcontents = aasworld.areasettings[reach->areanum].contents; - route->endtravelflags = AAS_TravelFlagForType_inline(reach->traveltype); - VectorCopy(reach->end, route->endpos); - // - curareanum = reach->areanum; - VectorCopy(reach->end, curorigin); - // - if (maxtime && route->time > maxtime) - break; - } //end while - if (curareanum != goalareanum) - return qfalse; - return qtrue; -} //end of the function AAS_PredictRoute -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_BridgeWalkable(int areanum) -{ - return qfalse; -} //end of the function AAS_BridgeWalkable -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_ReachabilityFromNum(int num, struct aas_reachability_s *reach) -{ - if (!aasworld.initialized) - { - Com_Memset(reach, 0, sizeof(aas_reachability_t)); - return; - } //end if - if (num < 0 || num >= aasworld.reachabilitysize) - { - Com_Memset(reach, 0, sizeof(aas_reachability_t)); - return; - } //end if - Com_Memcpy(reach, &aasworld.reachability[num], sizeof(aas_reachability_t));; -} //end of the function AAS_ReachabilityFromNum -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_NextAreaReachability(int areanum, int reachnum) -{ - aas_areasettings_t *settings; - - if (!aasworld.initialized) return 0; - - if (areanum <= 0 || areanum >= aasworld.numareas) - { - botimport.Print(PRT_ERROR, "AAS_NextAreaReachability: areanum %d out of range\n", areanum); - return 0; - } //end if - - settings = &aasworld.areasettings[areanum]; - if (!reachnum) - { - return settings->firstreachablearea; - } //end if - if (reachnum < settings->firstreachablearea) - { - botimport.Print(PRT_FATAL, "AAS_NextAreaReachability: reachnum < settings->firstreachableara"); - return 0; - } //end if - reachnum++; - if (reachnum >= settings->firstreachablearea + settings->numreachableareas) - { - return 0; - } //end if - return reachnum; -} //end of the function AAS_NextAreaReachability -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_NextModelReachability(int num, int modelnum) -{ - int i; - - if (num <= 0) num = 1; - else if (num >= aasworld.reachabilitysize) return 0; - else num++; - // - for (i = num; i < aasworld.reachabilitysize; i++) - { - if ((aasworld.reachability[i].traveltype & TRAVELTYPE_MASK) == TRAVEL_ELEVATOR) - { - if (aasworld.reachability[i].facenum == modelnum) return i; - } //end if - else if ((aasworld.reachability[i].traveltype & TRAVELTYPE_MASK) == TRAVEL_FUNCBOB) - { - if ((aasworld.reachability[i].facenum & 0x0000FFFF) == modelnum) return i; - } //end if - } //end for - return 0; -} //end of the function AAS_NextModelReachability -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_RandomGoalArea(int areanum, int travelflags, int *goalareanum, vec3_t goalorigin) -{ - int i, n, t; - vec3_t start, end; - aas_trace_t trace; - - //if the area has no reachabilities - if (!AAS_AreaReachability(areanum)) return qfalse; - // - n = aasworld.numareas * random(); - for (i = 0; i < aasworld.numareas; i++) - { - if (n <= 0) n = 1; - if (n >= aasworld.numareas) n = 1; - if (AAS_AreaReachability(n)) - { - t = AAS_AreaTravelTimeToGoalArea(areanum, aasworld.areas[areanum].center, n, travelflags); - //if the goal is reachable - if (t > 0) - { - if (AAS_AreaSwim(n)) - { - *goalareanum = n; - VectorCopy(aasworld.areas[n].center, goalorigin); - //botimport.Print(PRT_MESSAGE, "found random goal area %d\n", *goalareanum); - return qtrue; - } //end if - VectorCopy(aasworld.areas[n].center, start); - if (!AAS_PointAreaNum(start)) - Log_Write("area %d center %f %f %f in solid?", n, start[0], start[1], start[2]); - VectorCopy(start, end); - end[2] -= 300; - trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, -1); - if (!trace.startsolid && trace.fraction < 1 && AAS_PointAreaNum(trace.endpos) == n) - { - if (AAS_AreaGroundFaceArea(n) > 300) - { - *goalareanum = n; - VectorCopy(trace.endpos, goalorigin); - //botimport.Print(PRT_MESSAGE, "found random goal area %d\n", *goalareanum); - return qtrue; - } //end if - } //end if - } //end if - } //end if - n++; - } //end for - return qfalse; -} //end of the function AAS_RandomGoalArea -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_AreaVisible(int srcarea, int destarea) -{ - return qfalse; -} //end of the function AAS_AreaVisible -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -float DistancePointToLine(vec3_t v1, vec3_t v2, vec3_t point) -{ - vec3_t vec, p2; - - AAS_ProjectPointOntoVector(point, v1, v2, p2); - VectorSubtract(point, p2, vec); - return VectorLength(vec); -} //end of the function DistancePointToLine -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_NearestHideArea(int srcnum, vec3_t origin, int areanum, int enemynum, vec3_t enemyorigin, int enemyareanum, int travelflags) -{ - int i, j, nextareanum, badtravelflags, numreach, bestarea; - unsigned short int t, besttraveltime; - static unsigned short int *hidetraveltimes; - aas_routingupdate_t *updateliststart, *updatelistend, *curupdate, *nextupdate; - aas_reachability_t *reach; - float dist1, dist2; - vec3_t v1, v2, p; - qboolean startVisible; - - // - if (!hidetraveltimes) - { - hidetraveltimes = (unsigned short int *) GetClearedMemory(aasworld.numareas * sizeof(unsigned short int)); - } //end if - else - { - Com_Memset(hidetraveltimes, 0, aasworld.numareas * sizeof(unsigned short int)); - } //end else - besttraveltime = 0; - bestarea = 0; - //assume visible - startVisible = qtrue; - // - badtravelflags = ~travelflags; - // - curupdate = &aasworld.areaupdate[areanum]; - curupdate->areanum = areanum; - VectorCopy(origin, curupdate->start); - curupdate->areatraveltimes = aasworld.areatraveltimes[areanum][0]; - curupdate->tmptraveltime = 0; - //put the area to start with in the current read list - curupdate->next = NULL; - curupdate->prev = NULL; - updateliststart = curupdate; - updatelistend = curupdate; - //while there are updates in the list - while (updateliststart) - { - curupdate = updateliststart; - // - if (curupdate->next) curupdate->next->prev = NULL; - else updatelistend = NULL; - updateliststart = curupdate->next; - // - curupdate->inlist = qfalse; - //check all reversed reachability links - numreach = aasworld.areasettings[curupdate->areanum].numreachableareas; - reach = &aasworld.reachability[aasworld.areasettings[curupdate->areanum].firstreachablearea]; - // - for (i = 0; i < numreach; i++, reach++) - { - //if an undesired travel type is used - if (AAS_TravelFlagForType_inline(reach->traveltype) & badtravelflags) continue; - // - if (AAS_AreaContentsTravelFlags_inline(reach->areanum) & badtravelflags) continue; - //number of the area the reachability leads to - nextareanum = reach->areanum; - // if this moves us into the enemies area, skip it - if (nextareanum == enemyareanum) continue; - //time already travelled plus the traveltime through - //the current area plus the travel time from the reachability - t = curupdate->tmptraveltime + - AAS_AreaTravelTime(curupdate->areanum, curupdate->start, reach->start) + - reach->traveltime; - - //avoid going near the enemy - AAS_ProjectPointOntoVector(enemyorigin, curupdate->start, reach->end, p); - for (j = 0; j < 3; j++) - if ((p[j] > curupdate->start[j] && p[j] > reach->end[j]) || - (p[j] < curupdate->start[j] && p[j] < reach->end[j])) - break; - if (j < 3) - { - VectorSubtract(enemyorigin, reach->end, v2); - } //end if - else - { - VectorSubtract(enemyorigin, p, v2); - } //end else - dist2 = VectorLength(v2); - //never go through the enemy - if (dist2 < 40) continue; - // - VectorSubtract(enemyorigin, curupdate->start, v1); - dist1 = VectorLength(v1); - // - if (dist2 < dist1) - { - t += (dist1 - dist2) * 10; - } - // if we weren't visible when starting, make sure we don't move into their view - if (!startVisible && AAS_AreaVisible(enemyareanum, nextareanum)) { - continue; - } - // - if (besttraveltime && t >= besttraveltime) continue; - // - if (!hidetraveltimes[nextareanum] || - hidetraveltimes[nextareanum] > t) - { - //if the nextarea is not visible from the enemy area - if (!AAS_AreaVisible(enemyareanum, nextareanum)) - { - besttraveltime = t; - bestarea = nextareanum; - } //end if - hidetraveltimes[nextareanum] = t; - nextupdate = &aasworld.areaupdate[nextareanum]; - nextupdate->areanum = nextareanum; - nextupdate->tmptraveltime = t; - //remember where we entered this area - VectorCopy(reach->end, nextupdate->start); - //if this update is not in the list yet - if (!nextupdate->inlist) - { - //add the new update to the end of the list - nextupdate->next = NULL; - nextupdate->prev = updatelistend; - if (updatelistend) updatelistend->next = nextupdate; - else updateliststart = nextupdate; - updatelistend = nextupdate; - nextupdate->inlist = qtrue; - } //end if - } //end if - } //end for - } //end while - return bestarea; -} //end of the function AAS_NearestHideArea diff --git a/src/botlib/be_aas_route.h b/src/botlib/be_aas_route.h deleted file mode 100644 index 40b3394b..00000000 --- a/src/botlib/be_aas_route.h +++ /dev/null @@ -1,68 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_aas_route.h - * - * desc: AAS - * - * $Archive: /source/code/botlib/be_aas_route.h $ - * - *****************************************************************************/ - -#ifdef AASINTERN -//initialize the AAS routing -void AAS_InitRouting(void); -//free the AAS routing caches -void AAS_FreeRoutingCaches(void); -//returns the travel time from start to end in the given area -unsigned short int AAS_AreaTravelTime(int areanum, vec3_t start, vec3_t end); -// -void AAS_CreateAllRoutingCache(void); -void AAS_WriteRouteCache(void); -// -void AAS_RoutingInfo(void); -#endif //AASINTERN - -//returns the travel flag for the given travel type -int AAS_TravelFlagForType(int traveltype); -//return the travel flag(s) for traveling through this area -int AAS_AreaContentsTravelFlags(int areanum); -//returns the index of the next reachability for the given area -int AAS_NextAreaReachability(int areanum, int reachnum); -//returns the reachability with the given index -void AAS_ReachabilityFromNum(int num, struct aas_reachability_s *reach); -//returns a random goal area and goal origin -int AAS_RandomGoalArea(int areanum, int travelflags, int *goalareanum, vec3_t goalorigin); -//enable or disable an area for routing -int AAS_EnableRoutingArea(int areanum, int enable); -//returns the travel time within the given area from start to end -unsigned short int AAS_AreaTravelTime(int areanum, vec3_t start, vec3_t end); -//returns the travel time from the area to the goal area using the given travel flags -int AAS_AreaTravelTimeToGoalArea(int areanum, vec3_t origin, int goalareanum, int travelflags); -//predict a route up to a stop event -int AAS_PredictRoute(struct aas_predictroute_s *route, int areanum, vec3_t origin, - int goalareanum, int travelflags, int maxareas, int maxtime, - int stopevent, int stopcontents, int stoptfl, int stopareanum); - - diff --git a/src/botlib/be_aas_routealt.c b/src/botlib/be_aas_routealt.c deleted file mode 100644 index a851a36c..00000000 --- a/src/botlib/be_aas_routealt.c +++ /dev/null @@ -1,241 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_aas_routealt.c - * - * desc: AAS - * - * $Archive: /MissionPack/code/botlib/be_aas_routealt.c $ - * - *****************************************************************************/ - -#include "../qcommon/q_shared.h" -#include "l_utils.h" -#include "l_memory.h" -#include "l_log.h" -#include "l_script.h" -#include "l_precomp.h" -#include "l_struct.h" -#include "aasfile.h" -#include "botlib.h" -#include "be_aas.h" -#include "be_aas_funcs.h" -#include "be_interface.h" -#include "be_aas_def.h" - -#define ENABLE_ALTROUTING -//#define ALTROUTE_DEBUG - -typedef struct midrangearea_s -{ - int valid; - unsigned short starttime; - unsigned short goaltime; -} midrangearea_t; - -midrangearea_t *midrangeareas; -int *clusterareas; -int numclusterareas; - -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_AltRoutingFloodCluster_r(int areanum) -{ - int i, otherareanum; - aas_area_t *area; - aas_face_t *face; - - //add the current area to the areas of the current cluster - clusterareas[numclusterareas] = areanum; - numclusterareas++; - //remove the area from the mid range areas - midrangeareas[areanum].valid = qfalse; - //flood to other areas through the faces of this area - area = &aasworld.areas[areanum]; - for (i = 0; i < area->numfaces; i++) - { - face = &aasworld.faces[abs(aasworld.faceindex[area->firstface + i])]; - //get the area at the other side of the face - if (face->frontarea == areanum) otherareanum = face->backarea; - else otherareanum = face->frontarea; - //if there is an area at the other side of this face - if (!otherareanum) continue; - //if the other area is not a midrange area - if (!midrangeareas[otherareanum].valid) continue; - // - AAS_AltRoutingFloodCluster_r(otherareanum); - } //end for -} //end of the function AAS_AltRoutingFloodCluster_r -//=========================================================================== -// -// 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 -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_InitAlternativeRouting(void) -{ -#ifdef ENABLE_ALTROUTING - if (midrangeareas) FreeMemory(midrangeareas); - midrangeareas = (midrangearea_t *) GetMemory(aasworld.numareas * sizeof(midrangearea_t)); - if (clusterareas) FreeMemory(clusterareas); - clusterareas = (int *) GetMemory(aasworld.numareas * sizeof(int)); -#endif -} //end of the function AAS_InitAlternativeRouting -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_ShutdownAlternativeRouting(void) -{ -#ifdef ENABLE_ALTROUTING - if (midrangeareas) FreeMemory(midrangeareas); - midrangeareas = NULL; - if (clusterareas) FreeMemory(clusterareas); - clusterareas = NULL; - numclusterareas = 0; -#endif -} //end of the function AAS_ShutdownAlternativeRouting diff --git a/src/botlib/be_aas_routealt.h b/src/botlib/be_aas_routealt.h deleted file mode 100644 index 96c9d02d..00000000 --- a/src/botlib/be_aas_routealt.h +++ /dev/null @@ -1,41 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_aas_routealt.h - * - * desc: AAS - * - * $Archive: /source/code/botlib/be_aas_routealt.h $ - * - *****************************************************************************/ - -#ifdef AASINTERN -void AAS_InitAlternativeRouting(void); -void AAS_ShutdownAlternativeRouting(void); -#endif //AASINTERN - - -int AAS_AlternativeRouteGoals(vec3_t start, int startareanum, vec3_t goal, int goalareanum, int travelflags, - aas_altroutegoal_t *altroutegoals, int maxaltroutegoals, - int type); diff --git a/src/botlib/be_aas_sample.c b/src/botlib/be_aas_sample.c deleted file mode 100644 index 557860d4..00000000 --- a/src/botlib/be_aas_sample.c +++ /dev/null @@ -1,1395 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_aas_sample.c - * - * desc: AAS environment sampling - * - * $Archive: /MissionPack/code/botlib/be_aas_sample.c $ - * - *****************************************************************************/ - -#include "../qcommon/q_shared.h" -#include "l_memory.h" -#include "l_script.h" -#include "l_precomp.h" -#include "l_struct.h" -#ifndef BSPC -#include "l_libvar.h" -#endif -#include "aasfile.h" -#include "botlib.h" -#include "be_aas.h" -#include "be_interface.h" -#include "be_aas_funcs.h" -#include "be_aas_def.h" - -extern botlib_import_t botimport; - -//#define AAS_SAMPLE_DEBUG - -#define BBOX_NORMAL_EPSILON 0.001 - -#define ON_EPSILON 0 //0.0005 - -#define TRACEPLANE_EPSILON 0.125 - -typedef struct aas_tracestack_s -{ - vec3_t start; //start point of the piece of line to trace - vec3_t end; //end point of the piece of line to trace - int planenum; //last plane used as splitter - int nodenum; //node found after splitting with planenum -} aas_tracestack_t; - -int numaaslinks; - -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_PresenceTypeBoundingBox(int presencetype, vec3_t mins, vec3_t maxs) -{ - int index; - //bounding box size for each presence type - vec3_t boxmins[3] = {{0, 0, 0}, {-15, -15, -24}, {-15, -15, -24}}; - vec3_t boxmaxs[3] = {{0, 0, 0}, { 15, 15, 32}, { 15, 15, 8}}; - - if (presencetype == PRESENCE_NORMAL) index = 1; - else if (presencetype == PRESENCE_CROUCH) index = 2; - else - { - botimport.Print(PRT_FATAL, "AAS_PresenceTypeBoundingBox: unknown presence type\n"); - index = 2; - } //end if - VectorCopy(boxmins[index], mins); - VectorCopy(boxmaxs[index], maxs); -} //end of the function AAS_PresenceTypeBoundingBox -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_InitAASLinkHeap(void) -{ - int i, max_aaslinks; - - max_aaslinks = aasworld.linkheapsize; - //if there's no link heap present - if (!aasworld.linkheap) - { -#ifdef BSPC - max_aaslinks = 6144; -#else - max_aaslinks = (int) LibVarValue("max_aaslinks", "6144"); -#endif - if (max_aaslinks < 0) max_aaslinks = 0; - aasworld.linkheapsize = max_aaslinks; - aasworld.linkheap = (aas_link_t *) GetHunkMemory(max_aaslinks * sizeof(aas_link_t)); - } //end if - //link the links on the heap - aasworld.linkheap[0].prev_ent = NULL; - aasworld.linkheap[0].next_ent = &aasworld.linkheap[1]; - for (i = 1; i < max_aaslinks-1; i++) - { - aasworld.linkheap[i].prev_ent = &aasworld.linkheap[i - 1]; - aasworld.linkheap[i].next_ent = &aasworld.linkheap[i + 1]; - } //end for - aasworld.linkheap[max_aaslinks-1].prev_ent = &aasworld.linkheap[max_aaslinks-2]; - aasworld.linkheap[max_aaslinks-1].next_ent = NULL; - //pointer to the first free link - aasworld.freelinks = &aasworld.linkheap[0]; - // - numaaslinks = max_aaslinks; -} //end of the function AAS_InitAASLinkHeap -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_FreeAASLinkHeap(void) -{ - if (aasworld.linkheap) FreeMemory(aasworld.linkheap); - aasworld.linkheap = NULL; - aasworld.linkheapsize = 0; -} //end of the function AAS_FreeAASLinkHeap -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -aas_link_t *AAS_AllocAASLink(void) -{ - aas_link_t *link; - - link = aasworld.freelinks; - if (!link) - { -#ifndef BSPC - if (bot_developer) -#endif - { - botimport.Print(PRT_FATAL, "empty aas link heap\n"); - } //end if - return NULL; - } //end if - if (aasworld.freelinks) aasworld.freelinks = aasworld.freelinks->next_ent; - if (aasworld.freelinks) aasworld.freelinks->prev_ent = NULL; - numaaslinks--; - return link; -} //end of the function AAS_AllocAASLink -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_DeAllocAASLink(aas_link_t *link) -{ - if (aasworld.freelinks) aasworld.freelinks->prev_ent = link; - link->prev_ent = NULL; - link->next_ent = aasworld.freelinks; - link->prev_area = NULL; - link->next_area = NULL; - aasworld.freelinks = link; - numaaslinks++; -} //end of the function AAS_DeAllocAASLink -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_InitAASLinkedEntities(void) -{ - if (!aasworld.loaded) return; - if (aasworld.arealinkedentities) FreeMemory(aasworld.arealinkedentities); - aasworld.arealinkedentities = (aas_link_t **) GetClearedHunkMemory( - aasworld.numareas * sizeof(aas_link_t *)); -} //end of the function AAS_InitAASLinkedEntities -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_FreeAASLinkedEntities(void) -{ - if (aasworld.arealinkedentities) FreeMemory(aasworld.arealinkedentities); - aasworld.arealinkedentities = NULL; -} //end of the function AAS_InitAASLinkedEntities -//=========================================================================== -// returns the AAS area the point is in -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_PointAreaNum(vec3_t point) -{ - int nodenum; - vec_t dist; - aas_node_t *node; - aas_plane_t *plane; - - if (!aasworld.loaded) - { - botimport.Print(PRT_ERROR, "AAS_PointAreaNum: aas not loaded\n"); - return 0; - } //end if - - //start with node 1 because node zero is a dummy used for solid leafs - nodenum = 1; - while (nodenum > 0) - { -// botimport.Print(PRT_MESSAGE, "[%d]", nodenum); -#ifdef AAS_SAMPLE_DEBUG - if (nodenum >= aasworld.numnodes) - { - botimport.Print(PRT_ERROR, "nodenum = %d >= aasworld.numnodes = %d\n", nodenum, aasworld.numnodes); - return 0; - } //end if -#endif //AAS_SAMPLE_DEBUG - node = &aasworld.nodes[nodenum]; -#ifdef AAS_SAMPLE_DEBUG - if (node->planenum < 0 || node->planenum >= aasworld.numplanes) - { - botimport.Print(PRT_ERROR, "node->planenum = %d >= aasworld.numplanes = %d\n", node->planenum, aasworld.numplanes); - return 0; - } //end if -#endif //AAS_SAMPLE_DEBUG - plane = &aasworld.planes[node->planenum]; - dist = DotProduct(point, plane->normal) - plane->dist; - if (dist > 0) nodenum = node->children[0]; - else nodenum = node->children[1]; - } //end while - if (!nodenum) - { -#ifdef AAS_SAMPLE_DEBUG - botimport.Print(PRT_MESSAGE, "in solid\n"); -#endif //AAS_SAMPLE_DEBUG - return 0; - } //end if - return -nodenum; -} //end of the function AAS_PointAreaNum -//=========================================================================== -// -// 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 -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_AreaCluster(int areanum) -{ - if (areanum <= 0 || areanum >= aasworld.numareas) - { - botimport.Print(PRT_ERROR, "AAS_AreaCluster: invalid area number\n"); - return 0; - } //end if - return aasworld.areasettings[areanum].cluster; -} //end of the function AAS_AreaCluster -//=========================================================================== -// returns the presence types of the given area -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_AreaPresenceType(int areanum) -{ - if (!aasworld.loaded) return 0; - if (areanum <= 0 || areanum >= aasworld.numareas) - { - botimport.Print(PRT_ERROR, "AAS_AreaPresenceType: invalid area number\n"); - return 0; - } //end if - return aasworld.areasettings[areanum].presencetype; -} //end of the function AAS_AreaPresenceType -//=========================================================================== -// returns the presence type at the given point -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_PointPresenceType(vec3_t point) -{ - int areanum; - - if (!aasworld.loaded) return 0; - - areanum = AAS_PointAreaNum(point); - if (!areanum) return PRESENCE_NONE; - return aasworld.areasettings[areanum].presencetype; -} //end of the function AAS_PointPresenceType -//=========================================================================== -// calculates the minimum distance between the origin of the box and the -// given plane when both will collide on the given side of the plane -// -// normal = normal vector of plane to calculate distance from -// mins = minimums of box relative to origin -// maxs = maximums of box relative to origin -// side = side of the plane we want to calculate the distance from -// 0 normal vector side -// 1 not normal vector side -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -vec_t AAS_BoxOriginDistanceFromPlane(vec3_t normal, vec3_t mins, vec3_t maxs, int side) -{ - vec3_t v1, v2; - int i; - - //swap maxs and mins when on the other side of the plane - if (side) - { - //get a point of the box that would be one of the first - //to collide with the plane - for (i = 0; i < 3; i++) - { - if (normal[i] > BBOX_NORMAL_EPSILON) v1[i] = maxs[i]; - else if (normal[i] < -BBOX_NORMAL_EPSILON) v1[i] = mins[i]; - else v1[i] = 0; - } //end for - } //end if - else - { - //get a point of the box that would be one of the first - //to collide with the plane - for (i = 0; i < 3; i++) - { - if (normal[i] > BBOX_NORMAL_EPSILON) v1[i] = mins[i]; - else if (normal[i] < -BBOX_NORMAL_EPSILON) v1[i] = maxs[i]; - else v1[i] = 0; - } //end for - } //end else - // - VectorCopy(normal, v2); - VectorInverse(v2); -// VectorNegate(normal, v2); - return DotProduct(v1, v2); -} //end of the function AAS_BoxOriginDistanceFromPlane -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -qboolean AAS_AreaEntityCollision(int areanum, vec3_t start, vec3_t end, - int presencetype, int passent, aas_trace_t *trace) -{ - int collision; - vec3_t boxmins, boxmaxs; - aas_link_t *link; - bsp_trace_t bsptrace; - - AAS_PresenceTypeBoundingBox(presencetype, boxmins, boxmaxs); - - Com_Memset(&bsptrace, 0, sizeof(bsp_trace_t)); //make compiler happy - //assume no collision - bsptrace.fraction = 1; - collision = qfalse; - for (link = aasworld.arealinkedentities[areanum]; link; link = link->next_ent) - { - //ignore the pass entity - if (link->entnum == passent) continue; - // - if (AAS_EntityCollision(link->entnum, start, boxmins, boxmaxs, end, - CONTENTS_SOLID|CONTENTS_PLAYERCLIP, &bsptrace)) - { - collision = qtrue; - } //end if - } //end for - if (collision) - { - trace->startsolid = bsptrace.startsolid; - trace->ent = bsptrace.ent; - VectorCopy(bsptrace.endpos, trace->endpos); - trace->area = 0; - trace->planenum = 0; - return qtrue; - } //end if - return qfalse; -} //end of the function AAS_AreaEntityCollision -//=========================================================================== -// recursive subdivision of the line by the BSP tree. -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -aas_trace_t AAS_TraceClientBBox(vec3_t start, vec3_t end, int presencetype, - int passent) -{ - int side, nodenum, tmpplanenum; - float front, back, frac; - vec3_t cur_start, cur_end, cur_mid, v1, v2; - aas_tracestack_t tracestack[127]; - aas_tracestack_t *tstack_p; - aas_node_t *aasnode; - aas_plane_t *plane; - aas_trace_t trace; - - //clear the trace structure - Com_Memset(&trace, 0, sizeof(aas_trace_t)); - - if (!aasworld.loaded) return trace; - - tstack_p = tracestack; - //we start with the whole line on the stack - VectorCopy(start, tstack_p->start); - VectorCopy(end, tstack_p->end); - tstack_p->planenum = 0; - //start with node 1 because node zero is a dummy for a solid leaf - tstack_p->nodenum = 1; //starting at the root of the tree - tstack_p++; - - while (1) - { - //pop up the stack - tstack_p--; - //if the trace stack is empty (ended up with a piece of the - //line to be traced in an area) - if (tstack_p < tracestack) - { - tstack_p++; - //nothing was hit - trace.startsolid = qfalse; - trace.fraction = 1.0; - //endpos is the end of the line - VectorCopy(end, trace.endpos); - //nothing hit - trace.ent = 0; - trace.area = 0; - trace.planenum = 0; - return trace; - } //end if - //number of the current node to test the line against - nodenum = tstack_p->nodenum; - //if it is an area - if (nodenum < 0) - { -#ifdef AAS_SAMPLE_DEBUG - if (-nodenum > aasworld.numareasettings) - { - botimport.Print(PRT_ERROR, "AAS_TraceBoundingBox: -nodenum out of range\n"); - return trace; - } //end if -#endif //AAS_SAMPLE_DEBUG - //botimport.Print(PRT_MESSAGE, "areanum = %d, must be %d\n", -nodenum, AAS_PointAreaNum(start)); - //if can't enter the area because it hasn't got the right presence type - if (!(aasworld.areasettings[-nodenum].presencetype & presencetype)) - { - //if the start point is still the initial start point - //NOTE: no need for epsilons because the points will be - //exactly the same when they're both the start point - if (tstack_p->start[0] == start[0] && - tstack_p->start[1] == start[1] && - tstack_p->start[2] == start[2]) - { - trace.startsolid = qtrue; - trace.fraction = 0.0; - VectorClear(v1); - } //end if - else - { - trace.startsolid = qfalse; - VectorSubtract(end, start, v1); - VectorSubtract(tstack_p->start, start, v2); - trace.fraction = VectorLength(v2) / VectorNormalize(v1); - VectorMA(tstack_p->start, -0.125, v1, tstack_p->start); - } //end else - VectorCopy(tstack_p->start, trace.endpos); - trace.ent = 0; - trace.area = -nodenum; -// VectorSubtract(end, start, v1); - trace.planenum = tstack_p->planenum; - //always take the plane with normal facing towards the trace start - plane = &aasworld.planes[trace.planenum]; - if (DotProduct(v1, plane->normal) > 0) trace.planenum ^= 1; - return trace; - } //end if - else - { - if (passent >= 0) - { - if (AAS_AreaEntityCollision(-nodenum, tstack_p->start, - tstack_p->end, presencetype, passent, - &trace)) - { - if (!trace.startsolid) - { - VectorSubtract(end, start, v1); - VectorSubtract(trace.endpos, start, v2); - trace.fraction = VectorLength(v2) / VectorLength(v1); - } //end if - return trace; - } //end if - } //end if - } //end else - trace.lastarea = -nodenum; - continue; - } //end if - //if it is a solid leaf - if (!nodenum) - { - //if the start point is still the initial start point - //NOTE: no need for epsilons because the points will be - //exactly the same when they're both the start point - if (tstack_p->start[0] == start[0] && - tstack_p->start[1] == start[1] && - tstack_p->start[2] == start[2]) - { - trace.startsolid = qtrue; - trace.fraction = 0.0; - VectorClear(v1); - } //end if - else - { - trace.startsolid = qfalse; - VectorSubtract(end, start, v1); - VectorSubtract(tstack_p->start, start, v2); - trace.fraction = VectorLength(v2) / VectorNormalize(v1); - VectorMA(tstack_p->start, -0.125, v1, tstack_p->start); - } //end else - VectorCopy(tstack_p->start, trace.endpos); - trace.ent = 0; - trace.area = 0; //hit solid leaf -// VectorSubtract(end, start, v1); - trace.planenum = tstack_p->planenum; - //always take the plane with normal facing towards the trace start - plane = &aasworld.planes[trace.planenum]; - if (DotProduct(v1, plane->normal) > 0) trace.planenum ^= 1; - return trace; - } //end if -#ifdef AAS_SAMPLE_DEBUG - if (nodenum > aasworld.numnodes) - { - botimport.Print(PRT_ERROR, "AAS_TraceBoundingBox: nodenum out of range\n"); - return trace; - } //end if -#endif //AAS_SAMPLE_DEBUG - //the node to test against - aasnode = &aasworld.nodes[nodenum]; - //start point of current line to test against node - VectorCopy(tstack_p->start, cur_start); - //end point of the current line to test against node - VectorCopy(tstack_p->end, cur_end); - //the current node plane - plane = &aasworld.planes[aasnode->planenum]; - - switch(plane->type) - {/*FIXME: wtf doesn't this work? obviously the axial node planes aren't always facing positive!!! - //check for axial planes - case PLANE_X: - { - front = cur_start[0] - plane->dist; - back = cur_end[0] - plane->dist; - break; - } //end case - case PLANE_Y: - { - front = cur_start[1] - plane->dist; - back = cur_end[1] - plane->dist; - break; - } //end case - case PLANE_Z: - { - front = cur_start[2] - plane->dist; - back = cur_end[2] - plane->dist; - break; - } //end case*/ - default: //gee it's not an axial plane - { - front = DotProduct(cur_start, plane->normal) - plane->dist; - back = DotProduct(cur_end, plane->normal) - plane->dist; - break; - } //end default - } //end switch - // bk010221 - old location of FPE hack and divide by zero expression - //if the whole to be traced line is totally at the front of this node - //only go down the tree with the front child - if ((front >= -ON_EPSILON && back >= -ON_EPSILON)) - { - //keep the current start and end point on the stack - //and go down the tree with the front child - tstack_p->nodenum = aasnode->children[0]; - tstack_p++; - if (tstack_p >= &tracestack[127]) - { - botimport.Print(PRT_ERROR, "AAS_TraceBoundingBox: stack overflow\n"); - return trace; - } //end if - } //end if - //if the whole to be traced line is totally at the back of this node - //only go down the tree with the back child - else if ((front < ON_EPSILON && back < ON_EPSILON)) - { - //keep the current start and end point on the stack - //and go down the tree with the back child - tstack_p->nodenum = aasnode->children[1]; - tstack_p++; - if (tstack_p >= &tracestack[127]) - { - botimport.Print(PRT_ERROR, "AAS_TraceBoundingBox: stack overflow\n"); - return trace; - } //end if - } //end if - //go down the tree both at the front and back of the node - else - { - tmpplanenum = tstack_p->planenum; - // bk010221 - new location of divide by zero (see above) - if ( front == back ) front -= 0.001f; // bk0101022 - hack/FPE - //calculate the hitpoint with the node (split point of the line) - //put the crosspoint TRACEPLANE_EPSILON pixels on the near side - if (front < 0) frac = (front + TRACEPLANE_EPSILON)/(front-back); - else frac = (front - TRACEPLANE_EPSILON)/(front-back); // bk010221 - // - if (frac < 0) - frac = 0.001f; //0 - else if (frac > 1) - frac = 0.999f; //1 - //frac = front / (front-back); - // - cur_mid[0] = cur_start[0] + (cur_end[0] - cur_start[0]) * frac; - cur_mid[1] = cur_start[1] + (cur_end[1] - cur_start[1]) * frac; - cur_mid[2] = cur_start[2] + (cur_end[2] - cur_start[2]) * frac; - -// AAS_DrawPlaneCross(cur_mid, plane->normal, plane->dist, plane->type, LINECOLOR_RED); - //side the front part of the line is on - side = front < 0; - //first put the end part of the line on the stack (back side) - VectorCopy(cur_mid, tstack_p->start); - //not necesary to store because still on stack - //VectorCopy(cur_end, tstack_p->end); - tstack_p->planenum = aasnode->planenum; - tstack_p->nodenum = aasnode->children[!side]; - tstack_p++; - if (tstack_p >= &tracestack[127]) - { - botimport.Print(PRT_ERROR, "AAS_TraceBoundingBox: stack overflow\n"); - return trace; - } //end if - //now put the part near the start of the line on the stack so we will - //continue with thats part first. This way we'll find the first - //hit of the bbox - VectorCopy(cur_start, tstack_p->start); - VectorCopy(cur_mid, tstack_p->end); - tstack_p->planenum = tmpplanenum; - tstack_p->nodenum = aasnode->children[side]; - tstack_p++; - if (tstack_p >= &tracestack[127]) - { - botimport.Print(PRT_ERROR, "AAS_TraceBoundingBox: stack overflow\n"); - return trace; - } //end if - } //end else - } //end while -// return trace; -} //end of the function AAS_TraceClientBBox -//=========================================================================== -// recursive subdivision of the line by the BSP tree. -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_TraceAreas(vec3_t start, vec3_t end, int *areas, vec3_t *points, int maxareas) -{ - int side, nodenum, tmpplanenum; - int numareas; - float front, back, frac; - vec3_t cur_start, cur_end, cur_mid; - aas_tracestack_t tracestack[127]; - aas_tracestack_t *tstack_p; - aas_node_t *aasnode; - aas_plane_t *plane; - - numareas = 0; - areas[0] = 0; - if (!aasworld.loaded) return numareas; - - tstack_p = tracestack; - //we start with the whole line on the stack - VectorCopy(start, tstack_p->start); - VectorCopy(end, tstack_p->end); - tstack_p->planenum = 0; - //start with node 1 because node zero is a dummy for a solid leaf - tstack_p->nodenum = 1; //starting at the root of the tree - tstack_p++; - - while (1) - { - //pop up the stack - tstack_p--; - //if the trace stack is empty (ended up with a piece of the - //line to be traced in an area) - if (tstack_p < tracestack) - { - return numareas; - } //end if - //number of the current node to test the line against - nodenum = tstack_p->nodenum; - //if it is an area - if (nodenum < 0) - { -#ifdef AAS_SAMPLE_DEBUG - if (-nodenum > aasworld.numareasettings) - { - botimport.Print(PRT_ERROR, "AAS_TraceAreas: -nodenum = %d out of range\n", -nodenum); - return numareas; - } //end if -#endif //AAS_SAMPLE_DEBUG - //botimport.Print(PRT_MESSAGE, "areanum = %d, must be %d\n", -nodenum, AAS_PointAreaNum(start)); - areas[numareas] = -nodenum; - if (points) VectorCopy(tstack_p->start, points[numareas]); - numareas++; - if (numareas >= maxareas) return numareas; - continue; - } //end if - //if it is a solid leaf - if (!nodenum) - { - continue; - } //end if -#ifdef AAS_SAMPLE_DEBUG - if (nodenum > aasworld.numnodes) - { - botimport.Print(PRT_ERROR, "AAS_TraceAreas: nodenum out of range\n"); - return numareas; - } //end if -#endif //AAS_SAMPLE_DEBUG - //the node to test against - aasnode = &aasworld.nodes[nodenum]; - //start point of current line to test against node - VectorCopy(tstack_p->start, cur_start); - //end point of the current line to test against node - VectorCopy(tstack_p->end, cur_end); - //the current node plane - plane = &aasworld.planes[aasnode->planenum]; - - switch(plane->type) - {/*FIXME: wtf doesn't this work? obviously the node planes aren't always facing positive!!! - //check for axial planes - case PLANE_X: - { - front = cur_start[0] - plane->dist; - back = cur_end[0] - plane->dist; - break; - } //end case - case PLANE_Y: - { - front = cur_start[1] - plane->dist; - back = cur_end[1] - plane->dist; - break; - } //end case - case PLANE_Z: - { - front = cur_start[2] - plane->dist; - back = cur_end[2] - plane->dist; - break; - } //end case*/ - default: //gee it's not an axial plane - { - front = DotProduct(cur_start, plane->normal) - plane->dist; - back = DotProduct(cur_end, plane->normal) - plane->dist; - break; - } //end default - } //end switch - - //if the whole to be traced line is totally at the front of this node - //only go down the tree with the front child - if (front > 0 && back > 0) - { - //keep the current start and end point on the stack - //and go down the tree with the front child - tstack_p->nodenum = aasnode->children[0]; - tstack_p++; - if (tstack_p >= &tracestack[127]) - { - botimport.Print(PRT_ERROR, "AAS_TraceAreas: stack overflow\n"); - return numareas; - } //end if - } //end if - //if the whole to be traced line is totally at the back of this node - //only go down the tree with the back child - else if (front <= 0 && back <= 0) - { - //keep the current start and end point on the stack - //and go down the tree with the back child - tstack_p->nodenum = aasnode->children[1]; - tstack_p++; - if (tstack_p >= &tracestack[127]) - { - botimport.Print(PRT_ERROR, "AAS_TraceAreas: stack overflow\n"); - return numareas; - } //end if - } //end if - //go down the tree both at the front and back of the node - else - { - tmpplanenum = tstack_p->planenum; - //calculate the hitpoint with the node (split point of the line) - //put the crosspoint TRACEPLANE_EPSILON pixels on the near side - if (front < 0) frac = (front)/(front-back); - else frac = (front)/(front-back); - if (frac < 0) frac = 0; - else if (frac > 1) frac = 1; - //frac = front / (front-back); - // - cur_mid[0] = cur_start[0] + (cur_end[0] - cur_start[0]) * frac; - cur_mid[1] = cur_start[1] + (cur_end[1] - cur_start[1]) * frac; - cur_mid[2] = cur_start[2] + (cur_end[2] - cur_start[2]) * frac; - -// AAS_DrawPlaneCross(cur_mid, plane->normal, plane->dist, plane->type, LINECOLOR_RED); - //side the front part of the line is on - side = front < 0; - //first put the end part of the line on the stack (back side) - VectorCopy(cur_mid, tstack_p->start); - //not necesary to store because still on stack - //VectorCopy(cur_end, tstack_p->end); - tstack_p->planenum = aasnode->planenum; - tstack_p->nodenum = aasnode->children[!side]; - tstack_p++; - if (tstack_p >= &tracestack[127]) - { - botimport.Print(PRT_ERROR, "AAS_TraceAreas: stack overflow\n"); - return numareas; - } //end if - //now put the part near the start of the line on the stack so we will - //continue with thats part first. This way we'll find the first - //hit of the bbox - VectorCopy(cur_start, tstack_p->start); - VectorCopy(cur_mid, tstack_p->end); - tstack_p->planenum = tmpplanenum; - tstack_p->nodenum = aasnode->children[side]; - tstack_p++; - if (tstack_p >= &tracestack[127]) - { - botimport.Print(PRT_ERROR, "AAS_TraceAreas: stack overflow\n"); - return numareas; - } //end if - } //end else - } //end while -// return numareas; -} //end of the function AAS_TraceAreas -//=========================================================================== -// a simple cross product -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -// void AAS_OrthogonalToVectors(vec3_t v1, vec3_t v2, vec3_t res) -#define AAS_OrthogonalToVectors(v1, v2, res) \ - (res)[0] = ((v1)[1] * (v2)[2]) - ((v1)[2] * (v2)[1]);\ - (res)[1] = ((v1)[2] * (v2)[0]) - ((v1)[0] * (v2)[2]);\ - (res)[2] = ((v1)[0] * (v2)[1]) - ((v1)[1] * (v2)[0]); -//=========================================================================== -// tests if the given point is within the face boundaries -// -// Parameter: face : face to test if the point is in it -// pnormal : normal of the plane to use for the face -// point : point to test if inside face boundaries -// Returns: qtrue if the point is within the face boundaries -// Changes Globals: - -//=========================================================================== -qboolean AAS_InsideFace(aas_face_t *face, vec3_t pnormal, vec3_t point, float epsilon) -{ - int i, firstvertex, edgenum; - vec3_t v0; - vec3_t edgevec, pointvec, sepnormal; - aas_edge_t *edge; -#ifdef AAS_SAMPLE_DEBUG - int lastvertex = 0; -#endif //AAS_SAMPLE_DEBUG - - if (!aasworld.loaded) return qfalse; - - for (i = 0; i < face->numedges; i++) - { - edgenum = aasworld.edgeindex[face->firstedge + i]; - edge = &aasworld.edges[abs(edgenum)]; - //get the first vertex of the edge - firstvertex = edgenum < 0; - VectorCopy(aasworld.vertexes[edge->v[firstvertex]], v0); - //edge vector - VectorSubtract(aasworld.vertexes[edge->v[!firstvertex]], v0, edgevec); - // -#ifdef AAS_SAMPLE_DEBUG - if (lastvertex && lastvertex != edge->v[firstvertex]) - { - botimport.Print(PRT_MESSAGE, "winding not counter clockwise\n"); - } //end if - lastvertex = edge->v[!firstvertex]; -#endif //AAS_SAMPLE_DEBUG - //vector from first edge point to point possible in face - VectorSubtract(point, v0, pointvec); - //get a vector pointing inside the face orthogonal to both the - //edge vector and the normal vector of the plane the face is in - //this vector defines a plane through the origin (first vertex of - //edge) and through both the edge vector and the normal vector - //of the plane - AAS_OrthogonalToVectors(edgevec, pnormal, sepnormal); - //check on wich side of the above plane the point is - //this is done by checking the sign of the dot product of the - //vector orthogonal vector from above and the vector from the - //origin (first vertex of edge) to the point - //if the dotproduct is smaller than zero the point is outside the face - if (DotProduct(pointvec, sepnormal) < -epsilon) return qfalse; - } //end for - return qtrue; -} //end of the function AAS_InsideFace -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -qboolean AAS_PointInsideFace(int facenum, vec3_t point, float epsilon) -{ - int i, firstvertex, edgenum; - vec_t *v1, *v2; - vec3_t edgevec, pointvec, sepnormal; - aas_edge_t *edge; - aas_plane_t *plane; - aas_face_t *face; - - if (!aasworld.loaded) return qfalse; - - face = &aasworld.faces[facenum]; - plane = &aasworld.planes[face->planenum]; - // - for (i = 0; i < face->numedges; i++) - { - edgenum = aasworld.edgeindex[face->firstedge + i]; - edge = &aasworld.edges[abs(edgenum)]; - //get the first vertex of the edge - firstvertex = edgenum < 0; - v1 = aasworld.vertexes[edge->v[firstvertex]]; - v2 = aasworld.vertexes[edge->v[!firstvertex]]; - //edge vector - VectorSubtract(v2, v1, edgevec); - //vector from first edge point to point possible in face - VectorSubtract(point, v1, pointvec); - // - CrossProduct(edgevec, plane->normal, sepnormal); - // - if (DotProduct(pointvec, sepnormal) < -epsilon) return qfalse; - } //end for - return qtrue; -} //end of the function AAS_PointInsideFace -//=========================================================================== -// returns the ground face the given point is above in the given area -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -aas_face_t *AAS_AreaGroundFace(int areanum, vec3_t point) -{ - int i, facenum; - vec3_t up = {0, 0, 1}; - vec3_t normal; - aas_area_t *area; - aas_face_t *face; - - if (!aasworld.loaded) return NULL; - - area = &aasworld.areas[areanum]; - for (i = 0; i < area->numfaces; i++) - { - facenum = aasworld.faceindex[area->firstface + i]; - face = &aasworld.faces[abs(facenum)]; - //if this is a ground face - if (face->faceflags & FACE_GROUND) - { - //get the up or down normal - if (aasworld.planes[face->planenum].normal[2] < 0) VectorNegate(up, normal); - else VectorCopy(up, normal); - //check if the point is in the face - if (AAS_InsideFace(face, normal, point, 0.01f)) return face; - } //end if - } //end for - return NULL; -} //end of the function AAS_AreaGroundFace -//=========================================================================== -// returns the face the trace end position is situated in -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_FacePlane(int facenum, vec3_t normal, float *dist) -{ - aas_plane_t *plane; - - plane = &aasworld.planes[aasworld.faces[facenum].planenum]; - VectorCopy(plane->normal, normal); - *dist = plane->dist; -} //end of the function AAS_FacePlane -//=========================================================================== -// returns the face the trace end position is situated in -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -aas_face_t *AAS_TraceEndFace(aas_trace_t *trace) -{ - int i, facenum; - aas_area_t *area; - aas_face_t *face, *firstface = NULL; - - if (!aasworld.loaded) return NULL; - - //if started in solid no face was hit - if (trace->startsolid) return NULL; - //trace->lastarea is the last area the trace was in - area = &aasworld.areas[trace->lastarea]; - //check which face the trace.endpos was in - for (i = 0; i < area->numfaces; i++) - { - facenum = aasworld.faceindex[area->firstface + i]; - face = &aasworld.faces[abs(facenum)]; - //if the face is in the same plane as the trace end point - if ((face->planenum & ~1) == (trace->planenum & ~1)) - { - //firstface is used for optimization, if theres only one - //face in the plane then it has to be the good one - //if there are more faces in the same plane then always - //check the one with the fewest edges first -/* if (firstface) - { - if (firstface->numedges < face->numedges) - { - if (AAS_InsideFace(firstface, - aasworld.planes[face->planenum].normal, trace->endpos)) - { - return firstface; - } //end if - firstface = face; - } //end if - else - { - if (AAS_InsideFace(face, - aasworld.planes[face->planenum].normal, trace->endpos)) - { - return face; - } //end if - } //end else - } //end if - else - { - firstface = face; - } //end else*/ - if (AAS_InsideFace(face, - aasworld.planes[face->planenum].normal, trace->endpos, 0.01f)) return face; - } //end if - } //end for - return firstface; -} //end of the function AAS_TraceEndFace -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_BoxOnPlaneSide2(vec3_t absmins, vec3_t absmaxs, aas_plane_t *p) -{ - int i, sides; - float dist1, dist2; - vec3_t corners[2]; - - for (i = 0; i < 3; i++) - { - if (p->normal[i] < 0) - { - corners[0][i] = absmins[i]; - corners[1][i] = absmaxs[i]; - } //end if - else - { - corners[1][i] = absmins[i]; - corners[0][i] = absmaxs[i]; - } //end else - } //end for - dist1 = DotProduct(p->normal, corners[0]) - p->dist; - dist2 = DotProduct(p->normal, corners[1]) - p->dist; - sides = 0; - if (dist1 >= 0) sides = 1; - if (dist2 < 0) sides |= 2; - - return sides; -} //end of the function AAS_BoxOnPlaneSide2 -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -//int AAS_BoxOnPlaneSide(vec3_t absmins, vec3_t absmaxs, aas_plane_t *p) -#define AAS_BoxOnPlaneSide(absmins, absmaxs, p) (\ - ( (p)->type < 3) ?\ - (\ - ( (p)->dist <= (absmins)[(p)->type]) ?\ - (\ - 1\ - )\ - :\ - (\ - ( (p)->dist >= (absmaxs)[(p)->type]) ?\ - (\ - 2\ - )\ - :\ - (\ - 3\ - )\ - )\ - )\ - :\ - (\ - AAS_BoxOnPlaneSide2((absmins), (absmaxs), (p))\ - )\ -) //end of the function AAS_BoxOnPlaneSide -//=========================================================================== -// remove the links to this entity from all areas -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_UnlinkFromAreas(aas_link_t *areas) -{ - aas_link_t *link, *nextlink; - - for (link = areas; link; link = nextlink) - { - //next area the entity is linked in - nextlink = link->next_area; - //remove the entity from the linked list of this area - if (link->prev_ent) link->prev_ent->next_ent = link->next_ent; - else aasworld.arealinkedentities[link->areanum] = link->next_ent; - if (link->next_ent) link->next_ent->prev_ent = link->prev_ent; - //deallocate the link structure - AAS_DeAllocAASLink(link); - } //end for -} //end of the function AAS_UnlinkFromAreas -//=========================================================================== -// link the entity to the areas the bounding box is totally or partly -// situated in. This is done with recursion down the tree using the -// bounding box to test for plane sides -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== - -typedef struct -{ - int nodenum; //node found after splitting -} aas_linkstack_t; - -aas_link_t *AAS_AASLinkEntity(vec3_t absmins, vec3_t absmaxs, int entnum) -{ - int side, nodenum; - aas_linkstack_t linkstack[128]; - aas_linkstack_t *lstack_p; - aas_node_t *aasnode; - aas_plane_t *plane; - aas_link_t *link, *areas; - - if (!aasworld.loaded) - { - botimport.Print(PRT_ERROR, "AAS_LinkEntity: aas not loaded\n"); - return NULL; - } //end if - - areas = NULL; - // - lstack_p = linkstack; - //we start with the whole line on the stack - //start with node 1 because node zero is a dummy used for solid leafs - lstack_p->nodenum = 1; //starting at the root of the tree - lstack_p++; - - while (1) - { - //pop up the stack - lstack_p--; - //if the trace stack is empty (ended up with a piece of the - //line to be traced in an area) - if (lstack_p < linkstack) break; - //number of the current node to test the line against - nodenum = lstack_p->nodenum; - //if it is an area - if (nodenum < 0) - { - //NOTE: the entity might have already been linked into this area - // because several node children can point to the same area - for (link = aasworld.arealinkedentities[-nodenum]; link; link = link->next_ent) - { - if (link->entnum == entnum) break; - } //end for - if (link) continue; - // - link = AAS_AllocAASLink(); - if (!link) return areas; - link->entnum = entnum; - link->areanum = -nodenum; - //put the link into the double linked area list of the entity - link->prev_area = NULL; - link->next_area = areas; - if (areas) areas->prev_area = link; - areas = link; - //put the link into the double linked entity list of the area - link->prev_ent = NULL; - link->next_ent = aasworld.arealinkedentities[-nodenum]; - if (aasworld.arealinkedentities[-nodenum]) - aasworld.arealinkedentities[-nodenum]->prev_ent = link; - aasworld.arealinkedentities[-nodenum] = link; - // - continue; - } //end if - //if solid leaf - if (!nodenum) continue; - //the node to test against - aasnode = &aasworld.nodes[nodenum]; - //the current node plane - plane = &aasworld.planes[aasnode->planenum]; - //get the side(s) the box is situated relative to the plane - side = AAS_BoxOnPlaneSide2(absmins, absmaxs, plane); - //if on the front side of the node - if (side & 1) - { - lstack_p->nodenum = aasnode->children[0]; - lstack_p++; - } //end if - if (lstack_p >= &linkstack[127]) - { - botimport.Print(PRT_ERROR, "AAS_LinkEntity: stack overflow\n"); - break; - } //end if - //if on the back side of the node - if (side & 2) - { - lstack_p->nodenum = aasnode->children[1]; - lstack_p++; - } //end if - if (lstack_p >= &linkstack[127]) - { - botimport.Print(PRT_ERROR, "AAS_LinkEntity: stack overflow\n"); - break; - } //end if - } //end while - return areas; -} //end of the function AAS_AASLinkEntity -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -aas_link_t *AAS_LinkEntityClientBBox(vec3_t absmins, vec3_t absmaxs, int entnum, int presencetype) -{ - vec3_t mins, maxs; - vec3_t newabsmins, newabsmaxs; - - AAS_PresenceTypeBoundingBox(presencetype, mins, maxs); - VectorSubtract(absmins, maxs, newabsmins); - VectorSubtract(absmaxs, mins, newabsmaxs); - //relink the entity - return AAS_AASLinkEntity(newabsmins, newabsmaxs, entnum); -} //end of the function AAS_LinkEntityClientBBox -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_BBoxAreas(vec3_t absmins, vec3_t absmaxs, int *areas, int maxareas) -{ - aas_link_t *linkedareas, *link; - int num; - - linkedareas = AAS_AASLinkEntity(absmins, absmaxs, -1); - num = 0; - for (link = linkedareas; link; link = link->next_area) - { - areas[num] = link->areanum; - num++; - if (num >= maxareas) - break; - } //end for - AAS_UnlinkFromAreas(linkedareas); - return num; -} //end of the function AAS_BBoxAreas -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_AreaInfo( int areanum, aas_areainfo_t *info ) -{ - aas_areasettings_t *settings; - if (!info) - return 0; - if (areanum <= 0 || areanum >= aasworld.numareas) - { - botimport.Print(PRT_ERROR, "AAS_AreaInfo: areanum %d out of range\n", areanum); - return 0; - } //end if - settings = &aasworld.areasettings[areanum]; - info->cluster = settings->cluster; - info->contents = settings->contents; - info->flags = settings->areaflags; - info->presencetype = settings->presencetype; - VectorCopy(aasworld.areas[areanum].mins, info->mins); - VectorCopy(aasworld.areas[areanum].maxs, info->maxs); - VectorCopy(aasworld.areas[areanum].center, info->center); - return sizeof(aas_areainfo_t); -} //end of the function AAS_AreaInfo -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -aas_plane_t *AAS_PlaneFromNum(int planenum) -{ - if (!aasworld.loaded) return NULL; - - return &aasworld.planes[planenum]; -} //end of the function AAS_PlaneFromNum diff --git a/src/botlib/be_aas_sample.h b/src/botlib/be_aas_sample.h deleted file mode 100644 index a04425af..00000000 --- a/src/botlib/be_aas_sample.h +++ /dev/null @@ -1,70 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_aas_sample.h - * - * desc: AAS - * - * $Archive: /source/code/botlib/be_aas_sample.h $ - * - *****************************************************************************/ - -#ifdef AASINTERN -void AAS_InitAASLinkHeap(void); -void AAS_InitAASLinkedEntities(void); -void AAS_FreeAASLinkHeap(void); -void AAS_FreeAASLinkedEntities(void); -aas_face_t *AAS_AreaGroundFace(int areanum, vec3_t point); -aas_face_t *AAS_TraceEndFace(aas_trace_t *trace); -aas_plane_t *AAS_PlaneFromNum(int planenum); -aas_link_t *AAS_AASLinkEntity(vec3_t absmins, vec3_t absmaxs, int entnum); -aas_link_t *AAS_LinkEntityClientBBox(vec3_t absmins, vec3_t absmaxs, int entnum, int presencetype); -qboolean AAS_PointInsideFace(int facenum, vec3_t point, float epsilon); -qboolean AAS_InsideFace(aas_face_t *face, vec3_t pnormal, vec3_t point, float epsilon); -void AAS_UnlinkFromAreas(aas_link_t *areas); -#endif //AASINTERN - -//returns the mins and maxs of the bounding box for the given presence type -void AAS_PresenceTypeBoundingBox(int presencetype, vec3_t mins, vec3_t maxs); -//returns the cluster the area is in (negative portal number if the area is a portal) -int AAS_AreaCluster(int areanum); -//returns the presence type(s) of the area -int AAS_AreaPresenceType(int areanum); -//returns the presence type(s) at the given point -int AAS_PointPresenceType(vec3_t point); -//returns the result of the trace of a client bbox -aas_trace_t AAS_TraceClientBBox(vec3_t start, vec3_t end, int presencetype, int passent); -//stores the areas the trace went through and returns the number of passed areas -int AAS_TraceAreas(vec3_t start, vec3_t end, int *areas, vec3_t *points, int maxareas); -//returns the areas the bounding box is in -int AAS_BBoxAreas(vec3_t absmins, vec3_t absmaxs, int *areas, int maxareas); -//return area information -int AAS_AreaInfo( int areanum, aas_areainfo_t *info ); -//returns the area the point is in -int AAS_PointAreaNum(vec3_t point); -// -int AAS_PointReachabilityAreaIndex( vec3_t point ); -//returns the plane the given face is in -void AAS_FacePlane(int facenum, vec3_t normal, float *dist); - diff --git a/src/botlib/be_ai_char.c b/src/botlib/be_ai_char.c deleted file mode 100644 index 773cbeea..00000000 --- a/src/botlib/be_ai_char.c +++ /dev/null @@ -1,791 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_ai_char.c - * - * desc: bot characters - * - * $Archive: /MissionPack/code/botlib/be_ai_char.c $ - * - *****************************************************************************/ - -#include "../qcommon/q_shared.h" -#include "l_log.h" -#include "l_memory.h" -#include "l_utils.h" -#include "l_script.h" -#include "l_precomp.h" -#include "l_struct.h" -#include "l_libvar.h" -#include "aasfile.h" -#include "botlib.h" -#include "be_aas.h" -#include "be_aas_funcs.h" -#include "be_interface.h" -#include "be_ai_char.h" - -#define MAX_CHARACTERISTICS 80 - -#define CT_INTEGER 1 -#define CT_FLOAT 2 -#define CT_STRING 3 - -#define DEFAULT_CHARACTER "bots/default_c.c" - -//characteristic value -union cvalue -{ - int integer; - float _float; - char *string; -}; -//a characteristic -typedef struct bot_characteristic_s -{ - char type; //characteristic type - union cvalue value; //characteristic value -} bot_characteristic_t; - -//a bot character -typedef struct bot_character_s -{ - char filename[MAX_QPATH]; - float skill; - bot_characteristic_t c[1]; //variable sized -} bot_character_t; - -bot_character_t *botcharacters[MAX_CLIENTS + 1]; - -//======================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//======================================================================== -bot_character_t *BotCharacterFromHandle(int handle) -{ - if (handle <= 0 || handle > MAX_CLIENTS) - { - botimport.Print(PRT_FATAL, "character handle %d out of range\n", handle); - return NULL; - } //end if - if (!botcharacters[handle]) - { - botimport.Print(PRT_FATAL, "invalid character %d\n", handle); - return NULL; - } //end if - return botcharacters[handle]; -} //end of the function BotCharacterFromHandle -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotDumpCharacter(bot_character_t *ch) -{ - int i; - - Log_Write("%s", ch->filename); - Log_Write("skill %d\n", ch->skill); - Log_Write("{\n"); - for (i = 0; i < MAX_CHARACTERISTICS; i++) - { - switch(ch->c[i].type) - { - case CT_INTEGER: Log_Write(" %4d %d\n", i, ch->c[i].value.integer); break; - case CT_FLOAT: Log_Write(" %4d %f\n", i, ch->c[i].value._float); break; - case CT_STRING: Log_Write(" %4d %s\n", i, ch->c[i].value.string); break; - } //end case - } //end for - Log_Write("}\n"); -} //end of the function BotDumpCharacter -//======================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//======================================================================== -void BotFreeCharacterStrings(bot_character_t *ch) -{ - int i; - - for (i = 0; i < MAX_CHARACTERISTICS; i++) - { - if (ch->c[i].type == CT_STRING) - { - FreeMemory(ch->c[i].value.string); - } //end if - } //end for -} //end of the function BotFreeCharacterStrings -//======================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//======================================================================== -void BotFreeCharacter2(int handle) -{ - if (handle <= 0 || handle > MAX_CLIENTS) - { - botimport.Print(PRT_FATAL, "character handle %d out of range\n", handle); - return; - } //end if - if (!botcharacters[handle]) - { - botimport.Print(PRT_FATAL, "invalid character %d\n", handle); - return; - } //end if - BotFreeCharacterStrings(botcharacters[handle]); - FreeMemory(botcharacters[handle]); - botcharacters[handle] = NULL; -} //end of the function BotFreeCharacter2 -//======================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//======================================================================== -void BotFreeCharacter(int handle) -{ - if (!LibVarGetValue("bot_reloadcharacters")) return; - BotFreeCharacter2(handle); -} //end of the function BotFreeCharacter -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotDefaultCharacteristics(bot_character_t *ch, bot_character_t *defaultch) -{ - int i; - - for (i = 0; i < MAX_CHARACTERISTICS; i++) - { - if (ch->c[i].type) continue; - // - if (defaultch->c[i].type == CT_FLOAT) - { - ch->c[i].type = CT_FLOAT; - ch->c[i].value._float = defaultch->c[i].value._float; - } //end if - else if (defaultch->c[i].type == CT_INTEGER) - { - ch->c[i].type = CT_INTEGER; - ch->c[i].value.integer = defaultch->c[i].value.integer; - } //end else if - else if (defaultch->c[i].type == CT_STRING) - { - ch->c[i].type = CT_STRING; - ch->c[i].value.string = (char *) GetMemory(strlen(defaultch->c[i].value.string)+1); - strcpy(ch->c[i].value.string, defaultch->c[i].value.string); - } //end else if - } //end for -} //end of the function BotDefaultCharacteristics -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_character_t *BotLoadCharacterFromFile(char *charfile, int skill) -{ - int indent, index, foundcharacter; - bot_character_t *ch; - source_t *source; - token_t token; - - foundcharacter = qfalse; - //a bot character is parsed in two phases - PC_SetBaseFolder(BOTFILESBASEFOLDER); - source = LoadSourceFile(charfile); - if (!source) - { - botimport.Print(PRT_ERROR, "counldn't load %s\n", charfile); - return NULL; - } //end if - ch = (bot_character_t *) GetClearedMemory(sizeof(bot_character_t) + - MAX_CHARACTERISTICS * sizeof(bot_characteristic_t)); - strcpy(ch->filename, charfile); - while(PC_ReadToken(source, &token)) - { - if (!strcmp(token.string, "skill")) - { - if (!PC_ExpectTokenType(source, TT_NUMBER, 0, &token)) - { - FreeSource(source); - BotFreeCharacterStrings(ch); - FreeMemory(ch); - return NULL; - } //end if - if (!PC_ExpectTokenString(source, "{")) - { - FreeSource(source); - BotFreeCharacterStrings(ch); - FreeMemory(ch); - return NULL; - } //end if - //if it's the correct skill - if (skill < 0 || token.intvalue == skill) - { - foundcharacter = qtrue; - ch->skill = token.intvalue; - while(PC_ExpectAnyToken(source, &token)) - { - if (!strcmp(token.string, "}")) break; - if (token.type != TT_NUMBER || !(token.subtype & TT_INTEGER)) - { - SourceError(source, "expected integer index, found %s\n", token.string); - FreeSource(source); - BotFreeCharacterStrings(ch); - FreeMemory(ch); - return NULL; - } //end if - index = token.intvalue; - if (index < 0 || index > MAX_CHARACTERISTICS) - { - SourceError(source, "characteristic index out of range [0, %d]\n", MAX_CHARACTERISTICS); - FreeSource(source); - BotFreeCharacterStrings(ch); - FreeMemory(ch); - return NULL; - } //end if - if (ch->c[index].type) - { - SourceError(source, "characteristic %d already initialized\n", index); - FreeSource(source); - BotFreeCharacterStrings(ch); - FreeMemory(ch); - return NULL; - } //end if - if (!PC_ExpectAnyToken(source, &token)) - { - FreeSource(source); - BotFreeCharacterStrings(ch); - FreeMemory(ch); - return NULL; - } //end if - if (token.type == TT_NUMBER) - { - if (token.subtype & TT_FLOAT) - { - ch->c[index].value._float = token.floatvalue; - ch->c[index].type = CT_FLOAT; - } //end if - else - { - ch->c[index].value.integer = token.intvalue; - ch->c[index].type = CT_INTEGER; - } //end else - } //end if - else if (token.type == TT_STRING) - { - StripDoubleQuotes(token.string); - ch->c[index].value.string = GetMemory(strlen(token.string)+1); - strcpy(ch->c[index].value.string, token.string); - ch->c[index].type = CT_STRING; - } //end else if - else - { - SourceError(source, "expected integer, float or string, found %s\n", token.string); - FreeSource(source); - BotFreeCharacterStrings(ch); - FreeMemory(ch); - return NULL; - } //end else - } //end if - break; - } //end if - else - { - indent = 1; - while(indent) - { - if (!PC_ExpectAnyToken(source, &token)) - { - FreeSource(source); - BotFreeCharacterStrings(ch); - FreeMemory(ch); - return NULL; - } //end if - if (!strcmp(token.string, "{")) indent++; - else if (!strcmp(token.string, "}")) indent--; - } //end while - } //end else - } //end if - else - { - SourceError(source, "unknown definition %s\n", token.string); - FreeSource(source); - BotFreeCharacterStrings(ch); - FreeMemory(ch); - return NULL; - } //end else - } //end while - FreeSource(source); - // - if (!foundcharacter) - { - BotFreeCharacterStrings(ch); - FreeMemory(ch); - return NULL; - } //end if - return ch; -} //end of the function BotLoadCharacterFromFile -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotFindCachedCharacter(char *charfile, float skill) -{ - int handle; - - for (handle = 1; handle <= MAX_CLIENTS; handle++) - { - if ( !botcharacters[handle] ) continue; - if ( strcmp( botcharacters[handle]->filename, charfile ) == 0 && - (skill < 0 || fabs(botcharacters[handle]->skill - skill) < 0.01) ) - { - return handle; - } //end if - } //end for - return 0; -} //end of the function BotFindCachedCharacter -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotLoadCachedCharacter(char *charfile, float skill, int reload) -{ - int handle, cachedhandle, intskill; - bot_character_t *ch = NULL; -#ifdef DEBUG - int starttime; - - starttime = Sys_MilliSeconds(); -#endif //DEBUG - - //find a free spot for a character - for (handle = 1; handle <= MAX_CLIENTS; handle++) - { - if (!botcharacters[handle]) break; - } //end for - if (handle > MAX_CLIENTS) return 0; - //try to load a cached character with the given skill - if (!reload) - { - cachedhandle = BotFindCachedCharacter(charfile, skill); - if (cachedhandle) - { - botimport.Print(PRT_MESSAGE, "loaded cached skill %f from %s\n", skill, charfile); - return cachedhandle; - } //end if - } //end else - // - intskill = (int) (skill + 0.5); - //try to load the character with the given skill - ch = BotLoadCharacterFromFile(charfile, intskill); - if (ch) - { - botcharacters[handle] = ch; - // - botimport.Print(PRT_MESSAGE, "loaded skill %d from %s\n", intskill, charfile); -#ifdef DEBUG - if (bot_developer) - { - botimport.Print(PRT_MESSAGE, "skill %d loaded in %d msec from %s\n", intskill, Sys_MilliSeconds() - starttime, charfile); - } //end if -#endif //DEBUG - return handle; - } //end if - // - botimport.Print(PRT_WARNING, "couldn't find skill %d in %s\n", intskill, charfile); - // - if (!reload) - { - //try to load a cached default character with the given skill - cachedhandle = BotFindCachedCharacter(DEFAULT_CHARACTER, skill); - if (cachedhandle) - { - botimport.Print(PRT_MESSAGE, "loaded cached default skill %d from %s\n", intskill, charfile); - return cachedhandle; - } //end if - } //end if - //try to load the default character with the given skill - ch = BotLoadCharacterFromFile(DEFAULT_CHARACTER, intskill); - if (ch) - { - botcharacters[handle] = ch; - botimport.Print(PRT_MESSAGE, "loaded default skill %d from %s\n", intskill, charfile); - return handle; - } //end if - // - if (!reload) - { - //try to load a cached character with any skill - cachedhandle = BotFindCachedCharacter(charfile, -1); - if (cachedhandle) - { - botimport.Print(PRT_MESSAGE, "loaded cached skill %f from %s\n", botcharacters[cachedhandle]->skill, charfile); - return cachedhandle; - } //end if - } //end if - //try to load a character with any skill - ch = BotLoadCharacterFromFile(charfile, -1); - if (ch) - { - botcharacters[handle] = ch; - botimport.Print(PRT_MESSAGE, "loaded skill %f from %s\n", ch->skill, charfile); - return handle; - } //end if - // - if (!reload) - { - //try to load a cached character with any skill - cachedhandle = BotFindCachedCharacter(DEFAULT_CHARACTER, -1); - if (cachedhandle) - { - botimport.Print(PRT_MESSAGE, "loaded cached default skill %f from %s\n", botcharacters[cachedhandle]->skill, charfile); - return cachedhandle; - } //end if - } //end if - //try to load a character with any skill - ch = BotLoadCharacterFromFile(DEFAULT_CHARACTER, -1); - if (ch) - { - botcharacters[handle] = ch; - botimport.Print(PRT_MESSAGE, "loaded default skill %f from %s\n", ch->skill, charfile); - return handle; - } //end if - // - botimport.Print(PRT_WARNING, "couldn't load any skill from %s\n", charfile); - //couldn't load any character - return 0; -} //end of the function BotLoadCachedCharacter -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotLoadCharacterSkill(char *charfile, float skill) -{ - int ch, defaultch; - - defaultch = BotLoadCachedCharacter(DEFAULT_CHARACTER, skill, qfalse); - ch = BotLoadCachedCharacter(charfile, skill, LibVarGetValue("bot_reloadcharacters")); - - if (defaultch && ch) - { - BotDefaultCharacteristics(botcharacters[ch], botcharacters[defaultch]); - } //end if - - return ch; -} //end of the function BotLoadCharacterSkill -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotInterpolateCharacters(int handle1, int handle2, float desiredskill) -{ - bot_character_t *ch1, *ch2, *out; - int i, handle; - float scale; - - ch1 = BotCharacterFromHandle(handle1); - ch2 = BotCharacterFromHandle(handle2); - if (!ch1 || !ch2) - return 0; - //find a free spot for a character - for (handle = 1; handle <= MAX_CLIENTS; handle++) - { - if (!botcharacters[handle]) break; - } //end for - if (handle > MAX_CLIENTS) return 0; - out = (bot_character_t *) GetClearedMemory(sizeof(bot_character_t) + - MAX_CHARACTERISTICS * sizeof(bot_characteristic_t)); - out->skill = desiredskill; - strcpy(out->filename, ch1->filename); - botcharacters[handle] = out; - - scale = (float) (desiredskill - ch1->skill) / (ch2->skill - ch1->skill); - for (i = 0; i < MAX_CHARACTERISTICS; i++) - { - // - if (ch1->c[i].type == CT_FLOAT && ch2->c[i].type == CT_FLOAT) - { - out->c[i].type = CT_FLOAT; - out->c[i].value._float = ch1->c[i].value._float + - (ch2->c[i].value._float - ch1->c[i].value._float) * scale; - } //end if - else if (ch1->c[i].type == CT_INTEGER) - { - out->c[i].type = CT_INTEGER; - out->c[i].value.integer = ch1->c[i].value.integer; - } //end else if - else if (ch1->c[i].type == CT_STRING) - { - out->c[i].type = CT_STRING; - out->c[i].value.string = (char *) GetMemory(strlen(ch1->c[i].value.string)+1); - strcpy(out->c[i].value.string, ch1->c[i].value.string); - } //end else if - } //end for - return handle; -} //end of the function BotInterpolateCharacters -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotLoadCharacter(char *charfile, float skill) -{ - int firstskill, secondskill, handle; - - //make sure the skill is in the valid range - if (skill < 1.0) skill = 1.0; - else if (skill > 5.0) skill = 5.0; - //skill 1, 4 and 5 should be available in the character files - if (skill == 1.0 || skill == 4.0 || skill == 5.0) - { - return BotLoadCharacterSkill(charfile, skill); - } //end if - //check if there's a cached skill - handle = BotFindCachedCharacter(charfile, skill); - if (handle) - { - botimport.Print(PRT_MESSAGE, "loaded cached skill %f from %s\n", skill, charfile); - return handle; - } //end if - if (skill < 4.0) - { - //load skill 1 and 4 - firstskill = BotLoadCharacterSkill(charfile, 1); - if (!firstskill) return 0; - secondskill = BotLoadCharacterSkill(charfile, 4); - if (!secondskill) return firstskill; - } //end if - else - { - //load skill 4 and 5 - firstskill = BotLoadCharacterSkill(charfile, 4); - if (!firstskill) return 0; - secondskill = BotLoadCharacterSkill(charfile, 5); - if (!secondskill) return firstskill; - } //end else - //interpolate between the two skills - handle = BotInterpolateCharacters(firstskill, secondskill, skill); - if (!handle) return 0; - //write the character to the log file - BotDumpCharacter(botcharacters[handle]); - // - return handle; -} //end of the function BotLoadCharacter -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int CheckCharacteristicIndex(int character, int index) -{ - bot_character_t *ch; - - ch = BotCharacterFromHandle(character); - if (!ch) return qfalse; - if (index < 0 || index >= MAX_CHARACTERISTICS) - { - botimport.Print(PRT_ERROR, "characteristic %d does not exist\n", index); - return qfalse; - } //end if - if (!ch->c[index].type) - { - botimport.Print(PRT_ERROR, "characteristic %d is not initialized\n", index); - return qfalse; - } //end if - return qtrue; -} //end of the function CheckCharacteristicIndex -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -float Characteristic_Float(int character, int index) -{ - bot_character_t *ch; - - ch = BotCharacterFromHandle(character); - if (!ch) return 0; - //check if the index is in range - if (!CheckCharacteristicIndex(character, index)) return 0; - //an integer will be converted to a float - if (ch->c[index].type == CT_INTEGER) - { - return (float) ch->c[index].value.integer; - } //end if - //floats are just returned - else if (ch->c[index].type == CT_FLOAT) - { - return ch->c[index].value._float; - } //end else if - //cannot convert a string pointer to a float - else - { - botimport.Print(PRT_ERROR, "characteristic %d is not a float\n", index); - return 0; - } //end else if -// return 0; -} //end of the function Characteristic_Float -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -float Characteristic_BFloat(int character, int index, float min, float max) -{ - float value; - bot_character_t *ch; - - ch = BotCharacterFromHandle(character); - if (!ch) return 0; - if (min > max) - { - botimport.Print(PRT_ERROR, "cannot bound characteristic %d between %f and %f\n", index, min, max); - return 0; - } //end if - value = Characteristic_Float(character, index); - if (value < min) return min; - if (value > max) return max; - return value; -} //end of the function Characteristic_BFloat -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int Characteristic_Integer(int character, int index) -{ - bot_character_t *ch; - - ch = BotCharacterFromHandle(character); - if (!ch) return 0; - //check if the index is in range - if (!CheckCharacteristicIndex(character, index)) return 0; - //an integer will just be returned - if (ch->c[index].type == CT_INTEGER) - { - return ch->c[index].value.integer; - } //end if - //floats are casted to integers - else if (ch->c[index].type == CT_FLOAT) - { - return (int) ch->c[index].value._float; - } //end else if - else - { - botimport.Print(PRT_ERROR, "characteristic %d is not a integer\n", index); - return 0; - } //end else if -// return 0; -} //end of the function Characteristic_Integer -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int Characteristic_BInteger(int character, int index, int min, int max) -{ - int value; - bot_character_t *ch; - - ch = BotCharacterFromHandle(character); - if (!ch) return 0; - if (min > max) - { - botimport.Print(PRT_ERROR, "cannot bound characteristic %d between %d and %d\n", index, min, max); - return 0; - } //end if - value = Characteristic_Integer(character, index); - if (value < min) return min; - if (value > max) return max; - return value; -} //end of the function Characteristic_BInteger -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void Characteristic_String(int character, int index, char *buf, int size) -{ - bot_character_t *ch; - - ch = BotCharacterFromHandle(character); - if (!ch) return; - //check if the index is in range - if (!CheckCharacteristicIndex(character, index)) return; - //an integer will be converted to a float - if (ch->c[index].type == CT_STRING) - { - strncpy(buf, ch->c[index].value.string, size-1); - buf[size-1] = '\0'; - return; - } //end if - else - { - botimport.Print(PRT_ERROR, "characteristic %d is not a string\n", index); - return; - } //end else if - return; -} //end of the function Characteristic_String -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotShutdownCharacters(void) -{ - int handle; - - for (handle = 1; handle <= MAX_CLIENTS; handle++) - { - if (botcharacters[handle]) - { - BotFreeCharacter2(handle); - } //end if - } //end for -} //end of the function BotShutdownCharacters - diff --git a/src/botlib/be_ai_char.h b/src/botlib/be_ai_char.h deleted file mode 100644 index aa5fff3c..00000000 --- a/src/botlib/be_ai_char.h +++ /dev/null @@ -1,49 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// - -/***************************************************************************** - * name: be_ai_char.h - * - * desc: bot characters - * - * $Archive: /source/code/botlib/be_ai_char.h $ - * - *****************************************************************************/ - -//loads a bot character from a file -int BotLoadCharacter(char *charfile, float skill); -//frees a bot character -void BotFreeCharacter(int character); -//returns a float characteristic -float Characteristic_Float(int character, int index); -//returns a bounded float characteristic -float Characteristic_BFloat(int character, int index, float min, float max); -//returns an integer characteristic -int Characteristic_Integer(int character, int index); -//returns a bounded integer characteristic -int Characteristic_BInteger(int character, int index, int min, int max); -//returns a string characteristic -void Characteristic_String(int character, int index, char *buf, int size); -//free cached bot characters -void BotShutdownCharacters(void); diff --git a/src/botlib/be_ai_chat.c b/src/botlib/be_ai_chat.c deleted file mode 100644 index 98ca1c3d..00000000 --- a/src/botlib/be_ai_chat.c +++ /dev/null @@ -1,3030 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_ai_chat.c - * - * desc: bot chat AI - * - * $Archive: /MissionPack/code/botlib/be_ai_chat.c $ - * - *****************************************************************************/ - -#include "../qcommon/q_shared.h" -#include "l_memory.h" -#include "l_libvar.h" -#include "l_script.h" -#include "l_precomp.h" -#include "l_struct.h" -#include "l_utils.h" -#include "l_log.h" -#include "aasfile.h" -#include "botlib.h" -#include "be_aas.h" -#include "be_aas_funcs.h" -#include "be_interface.h" -#include "be_ea.h" -#include "be_ai_chat.h" - - -//escape character -#define ESCAPE_CHAR 0x01 //'_' -// -// "hi ", people, " ", 0, " entered the game" -//becomes: -// "hi _rpeople_ _v0_ entered the game" -// - -//match piece types -#define MT_VARIABLE 1 //variable match piece -#define MT_STRING 2 //string match piece -//reply chat key flags -#define RCKFL_AND 1 //key must be present -#define RCKFL_NOT 2 //key must be absent -#define RCKFL_NAME 4 //name of bot must be present -#define RCKFL_STRING 8 //key is a string -#define RCKFL_VARIABLES 16 //key is a match template -#define RCKFL_BOTNAMES 32 //key is a series of botnames -#define RCKFL_GENDERFEMALE 64 //bot must be female -#define RCKFL_GENDERMALE 128 //bot must be male -#define RCKFL_GENDERLESS 256 //bot must be genderless -//time to ignore a chat message after using it -#define CHATMESSAGE_RECENTTIME 20 - -//the actuall chat messages -typedef struct bot_chatmessage_s -{ - char *chatmessage; //chat message string - float time; //last time used - struct bot_chatmessage_s *next; //next chat message in a list -} bot_chatmessage_t; -//bot chat type with chat lines -typedef struct bot_chattype_s -{ - char name[MAX_CHATTYPE_NAME]; - int numchatmessages; - bot_chatmessage_t *firstchatmessage; - struct bot_chattype_s *next; -} bot_chattype_t; -//bot chat lines -typedef struct bot_chat_s -{ - bot_chattype_t *types; -} bot_chat_t; - -//random string -typedef struct bot_randomstring_s -{ - char *string; - struct bot_randomstring_s *next; -} bot_randomstring_t; -//list with random strings -typedef struct bot_randomlist_s -{ - char *string; - int numstrings; - bot_randomstring_t *firstrandomstring; - struct bot_randomlist_s *next; -} bot_randomlist_t; - -//synonym -typedef struct bot_synonym_s -{ - char *string; - float weight; - struct bot_synonym_s *next; -} bot_synonym_t; -//list with synonyms -typedef struct bot_synonymlist_s -{ - unsigned long int context; - float totalweight; - bot_synonym_t *firstsynonym; - struct bot_synonymlist_s *next; -} bot_synonymlist_t; - -//fixed match string -typedef struct bot_matchstring_s -{ - char *string; - struct bot_matchstring_s *next; -} bot_matchstring_t; - -//piece of a match template -typedef struct bot_matchpiece_s -{ - int type; - bot_matchstring_t *firststring; - int variable; - struct bot_matchpiece_s *next; -} bot_matchpiece_t; -//match template -typedef struct bot_matchtemplate_s -{ - unsigned long int context; - int type; - int subtype; - bot_matchpiece_t *first; - struct bot_matchtemplate_s *next; -} bot_matchtemplate_t; - -//reply chat key -typedef struct bot_replychatkey_s -{ - int flags; - char *string; - bot_matchpiece_t *match; - struct bot_replychatkey_s *next; -} bot_replychatkey_t; -//reply chat -typedef struct bot_replychat_s -{ - bot_replychatkey_t *keys; - float priority; - int numchatmessages; - bot_chatmessage_t *firstchatmessage; - struct bot_replychat_s *next; -} bot_replychat_t; - -//string list -typedef struct bot_stringlist_s -{ - char *string; - struct bot_stringlist_s *next; -} bot_stringlist_t; - -//chat state of a bot -typedef struct bot_chatstate_s -{ - int gender; //0=it, 1=female, 2=male - int client; //client number - char name[32]; //name of the bot - char chatmessage[MAX_MESSAGE_SIZE]; - int handle; - //the console messages visible to the bot - bot_consolemessage_t *firstmessage; //first message is the first typed message - bot_consolemessage_t *lastmessage; //last message is the last typed message, bottom of console - //number of console messages stored in the state - int numconsolemessages; - //the bot chat lines - bot_chat_t *chat; -} bot_chatstate_t; - -typedef struct { - bot_chat_t *chat; - char filename[MAX_QPATH]; - char chatname[MAX_QPATH]; -} bot_ichatdata_t; - -bot_ichatdata_t *ichatdata[MAX_CLIENTS]; - -bot_chatstate_t *botchatstates[MAX_CLIENTS+1]; -//console message heap -bot_consolemessage_t *consolemessageheap = NULL; -bot_consolemessage_t *freeconsolemessages = NULL; -//list with match strings -bot_matchtemplate_t *matchtemplates = NULL; -//list with synonyms -bot_synonymlist_t *synonyms = NULL; -//list with random strings -bot_randomlist_t *randomstrings = NULL; -//reply chats -bot_replychat_t *replychats = NULL; - -//======================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//======================================================================== -bot_chatstate_t *BotChatStateFromHandle(int handle) -{ - if (handle <= 0 || handle > MAX_CLIENTS) - { - botimport.Print(PRT_FATAL, "chat state handle %d out of range\n", handle); - return NULL; - } //end if - if (!botchatstates[handle]) - { - botimport.Print(PRT_FATAL, "invalid chat state %d\n", handle); - return NULL; - } //end if - return botchatstates[handle]; -} //end of the function BotChatStateFromHandle -//=========================================================================== -// initialize the heap with unused console messages -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void InitConsoleMessageHeap(void) -{ - int i, max_messages; - - if (consolemessageheap) FreeMemory(consolemessageheap); - // - max_messages = (int) LibVarValue("max_messages", "1024"); - consolemessageheap = (bot_consolemessage_t *) GetClearedHunkMemory(max_messages * - sizeof(bot_consolemessage_t)); - consolemessageheap[0].prev = NULL; - consolemessageheap[0].next = &consolemessageheap[1]; - for (i = 1; i < max_messages-1; i++) - { - consolemessageheap[i].prev = &consolemessageheap[i - 1]; - consolemessageheap[i].next = &consolemessageheap[i + 1]; - } //end for - consolemessageheap[max_messages-1].prev = &consolemessageheap[max_messages-2]; - consolemessageheap[max_messages-1].next = NULL; - //pointer to the free console messages - freeconsolemessages = consolemessageheap; -} //end of the function InitConsoleMessageHeap -//=========================================================================== -// allocate one console message from the heap -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_consolemessage_t *AllocConsoleMessage(void) -{ - bot_consolemessage_t *message; - message = freeconsolemessages; - if (freeconsolemessages) freeconsolemessages = freeconsolemessages->next; - if (freeconsolemessages) freeconsolemessages->prev = NULL; - return message; -} //end of the function AllocConsoleMessage -//=========================================================================== -// deallocate one console message from the heap -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void FreeConsoleMessage(bot_consolemessage_t *message) -{ - if (freeconsolemessages) freeconsolemessages->prev = message; - message->prev = NULL; - message->next = freeconsolemessages; - freeconsolemessages = message; -} //end of the function FreeConsoleMessage -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotRemoveConsoleMessage(int chatstate, int handle) -{ - bot_consolemessage_t *m, *nextm; - bot_chatstate_t *cs; - - cs = BotChatStateFromHandle(chatstate); - if (!cs) return; - - for (m = cs->firstmessage; m; m = nextm) - { - nextm = m->next; - if (m->handle == handle) - { - if (m->next) m->next->prev = m->prev; - else cs->lastmessage = m->prev; - if (m->prev) m->prev->next = m->next; - else cs->firstmessage = m->next; - - FreeConsoleMessage(m); - cs->numconsolemessages--; - break; - } //end if - } //end for -} //end of the function BotRemoveConsoleMessage -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotQueueConsoleMessage(int chatstate, int type, char *message) -{ - bot_consolemessage_t *m; - bot_chatstate_t *cs; - - cs = BotChatStateFromHandle(chatstate); - if (!cs) return; - - m = AllocConsoleMessage(); - if (!m) - { - botimport.Print(PRT_ERROR, "empty console message heap\n"); - return; - } //end if - cs->handle++; - if (cs->handle <= 0 || cs->handle > 8192) cs->handle = 1; - m->handle = cs->handle; - m->time = AAS_Time(); - m->type = type; - strncpy(m->message, message, MAX_MESSAGE_SIZE); - m->next = NULL; - if (cs->lastmessage) - { - cs->lastmessage->next = m; - m->prev = cs->lastmessage; - cs->lastmessage = m; - } //end if - else - { - cs->lastmessage = m; - cs->firstmessage = m; - m->prev = NULL; - } //end if - cs->numconsolemessages++; -} //end of the function BotQueueConsoleMessage -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotNextConsoleMessage(int chatstate, bot_consolemessage_t *cm) -{ - bot_chatstate_t *cs; - - cs = BotChatStateFromHandle(chatstate); - if (!cs) return 0; - if (cs->firstmessage) - { - Com_Memcpy(cm, cs->firstmessage, sizeof(bot_consolemessage_t)); - cm->next = cm->prev = NULL; - return cm->handle; - } //end if - return 0; -} //end of the function BotConsoleMessage -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotNumConsoleMessages(int chatstate) -{ - bot_chatstate_t *cs; - - cs = BotChatStateFromHandle(chatstate); - if (!cs) return 0; - return cs->numconsolemessages; -} //end of the function BotNumConsoleMessages -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int IsWhiteSpace(char c) -{ - if ((c >= 'a' && c <= 'z') - || (c >= 'A' && c <= 'Z') - || (c >= '0' && c <= '9') - || c == '(' || c == ')' - || c == '?' || c == ':' - || c == '\''|| c == '/' - || c == ',' || c == '.' - || c == '[' || c == ']' - || c == '-' || c == '_' - || c == '+' || c == '=') return qfalse; - return qtrue; -} //end of the function IsWhiteSpace -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotRemoveTildes(char *message) -{ - int i; - - //remove all tildes from the chat message - for (i = 0; message[i]; i++) - { - if (message[i] == '~') - { - memmove(&message[i], &message[i+1], strlen(&message[i+1])+1); - } //end if - } //end for -} //end of the function BotRemoveTildes -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void UnifyWhiteSpaces(char *string) -{ - char *ptr, *oldptr; - - for (ptr = oldptr = string; *ptr; oldptr = ptr) - { - while(*ptr && IsWhiteSpace(*ptr)) ptr++; - if (ptr > oldptr) - { - //if not at the start and not at the end of the string - //write only one space - if (oldptr > string && *ptr) *oldptr++ = ' '; - //remove all other white spaces - if (ptr > oldptr) memmove(oldptr, ptr, strlen(ptr)+1); - } //end if - while(*ptr && !IsWhiteSpace(*ptr)) ptr++; - } //end while -} //end of the function UnifyWhiteSpaces -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int StringContains(char *str1, char *str2, int casesensitive) -{ - int len, i, j, index; - - if (str1 == NULL || str2 == NULL) return -1; - - len = strlen(str1) - strlen(str2); - index = 0; - for (i = 0; i <= len; i++, str1++, index++) - { - for (j = 0; str2[j]; j++) - { - if (casesensitive) - { - if (str1[j] != str2[j]) break; - } //end if - else - { - if (toupper(str1[j]) != toupper(str2[j])) break; - } //end else - } //end for - if (!str2[j]) return index; - } //end for - return -1; -} //end of the function StringContains -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -char *StringContainsWord(char *str1, char *str2, int casesensitive) -{ - int len, i, j; - - len = strlen(str1) - strlen(str2); - for (i = 0; i <= len; i++, str1++) - { - //if not at the start of the string - if (i) - { - //skip to the start of the next word - while(*str1 && *str1 != ' ' && *str1 != '.' && *str1 != ',' && *str1 != '!') str1++; - if (!*str1) break; - str1++; - } //end for - //compare the word - for (j = 0; str2[j]; j++) - { - if (casesensitive) - { - if (str1[j] != str2[j]) break; - } //end if - else - { - if (toupper(str1[j]) != toupper(str2[j])) break; - } //end else - } //end for - //if there was a word match - if (!str2[j]) - { - //if the first string has an end of word - if (!str1[j] || str1[j] == ' ' || str1[j] == '.' || str1[j] == ',' || str1[j] == '!') return str1; - } //end if - } //end for - return NULL; -} //end of the function StringContainsWord -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void StringReplaceWords(char *string, char *synonym, char *replacement) -{ - char *str, *str2; - - //find the synonym in the string - str = StringContainsWord(string, synonym, qfalse); - //if the synonym occured in the string - while(str) - { - //if the synonym isn't part of the replacement which is already in the string - //usefull for abreviations - str2 = StringContainsWord(string, replacement, qfalse); - while(str2) - { - if (str2 <= str && str < str2 + strlen(replacement)) break; - str2 = StringContainsWord(str2+1, replacement, qfalse); - } //end while - if (!str2) - { - memmove(str + strlen(replacement), str+strlen(synonym), strlen(str+strlen(synonym))+1); - //append the synonum replacement - Com_Memcpy(str, replacement, strlen(replacement)); - } //end if - //find the next synonym in the string - str = StringContainsWord(str+strlen(replacement), synonym, qfalse); - } //end if -} //end of the function StringReplaceWords -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotDumpSynonymList(bot_synonymlist_t *synlist) -{ - FILE *fp; - bot_synonymlist_t *syn; - bot_synonym_t *synonym; - - fp = Log_FilePointer(); - if (!fp) return; - for (syn = synlist; syn; syn = syn->next) - { - fprintf(fp, "%ld : [", syn->context); - for (synonym = syn->firstsynonym; synonym; synonym = synonym->next) - { - fprintf(fp, "(\"%s\", %1.2f)", synonym->string, synonym->weight); - if (synonym->next) fprintf(fp, ", "); - } //end for - fprintf(fp, "]\n"); - } //end for -} //end of the function BotDumpSynonymList -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_synonymlist_t *BotLoadSynonyms(char *filename) -{ - int pass, size, contextlevel, numsynonyms; - unsigned long int context, contextstack[32]; - char *ptr = NULL; - source_t *source; - token_t token; - bot_synonymlist_t *synlist, *lastsyn, *syn; - bot_synonym_t *synonym, *lastsynonym; - - size = 0; - synlist = NULL; //make compiler happy - syn = NULL; //make compiler happy - synonym = NULL; //make compiler happy - //the synonyms are parsed in two phases - for (pass = 0; pass < 2; pass++) - { - // - if (pass && size) ptr = (char *) GetClearedHunkMemory(size); - // - PC_SetBaseFolder(BOTFILESBASEFOLDER); - source = LoadSourceFile(filename); - if (!source) - { - botimport.Print(PRT_ERROR, "counldn't load %s\n", filename); - return NULL; - } //end if - // - context = 0; - contextlevel = 0; - synlist = NULL; //list synonyms - lastsyn = NULL; //last synonym in the list - // - while(PC_ReadToken(source, &token)) - { - if (token.type == TT_NUMBER) - { - context |= token.intvalue; - contextstack[contextlevel] = token.intvalue; - contextlevel++; - if (contextlevel >= 32) - { - SourceError(source, "more than 32 context levels"); - FreeSource(source); - return NULL; - } //end if - if (!PC_ExpectTokenString(source, "{")) - { - FreeSource(source); - return NULL; - } //end if - } //end if - else if (token.type == TT_PUNCTUATION) - { - if (!strcmp(token.string, "}")) - { - contextlevel--; - if (contextlevel < 0) - { - SourceError(source, "too many }"); - FreeSource(source); - return NULL; - } //end if - context &= ~contextstack[contextlevel]; - } //end if - else if (!strcmp(token.string, "[")) - { - size += sizeof(bot_synonymlist_t); - if (pass) - { - syn = (bot_synonymlist_t *) ptr; - ptr += sizeof(bot_synonymlist_t); - syn->context = context; - syn->firstsynonym = NULL; - syn->next = NULL; - if (lastsyn) lastsyn->next = syn; - else synlist = syn; - lastsyn = syn; - } //end if - numsynonyms = 0; - lastsynonym = NULL; - while(1) - { - size_t len; - if (!PC_ExpectTokenString(source, "(") || - !PC_ExpectTokenType(source, TT_STRING, 0, &token)) - { - FreeSource(source); - return NULL; - } //end if - StripDoubleQuotes(token.string); - if (strlen(token.string) <= 0) - { - SourceError(source, "empty string", token.string); - FreeSource(source); - return NULL; - } //end if - len = strlen(token.string) + 1; - len = PAD(len, sizeof(long)); - size += sizeof(bot_synonym_t) + len; - if (pass) - { - synonym = (bot_synonym_t *) ptr; - ptr += sizeof(bot_synonym_t); - synonym->string = ptr; - ptr += len; - strcpy(synonym->string, token.string); - // - if (lastsynonym) lastsynonym->next = synonym; - else syn->firstsynonym = synonym; - lastsynonym = synonym; - } //end if - numsynonyms++; - if (!PC_ExpectTokenString(source, ",") || - !PC_ExpectTokenType(source, TT_NUMBER, 0, &token) || - !PC_ExpectTokenString(source, ")")) - { - FreeSource(source); - return NULL; - } //end if - if (pass) - { - synonym->weight = token.floatvalue; - syn->totalweight += synonym->weight; - } //end if - if (PC_CheckTokenString(source, "]")) break; - if (!PC_ExpectTokenString(source, ",")) - { - FreeSource(source); - return NULL; - } //end if - } //end while - if (numsynonyms < 2) - { - SourceError(source, "synonym must have at least two entries\n"); - FreeSource(source); - return NULL; - } //end if - } //end else - else - { - SourceError(source, "unexpected %s", token.string); - FreeSource(source); - return NULL; - } //end if - } //end else if - } //end while - // - FreeSource(source); - // - if (contextlevel > 0) - { - SourceError(source, "missing }"); - return NULL; - } //end if - } //end for - botimport.Print(PRT_MESSAGE, "loaded %s\n", filename); - // - //BotDumpSynonymList(synlist); - // - return synlist; -} //end of the function BotLoadSynonyms -//=========================================================================== -// replace all the synonyms in the string -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotReplaceSynonyms(char *string, unsigned long int context) -{ - bot_synonymlist_t *syn; - bot_synonym_t *synonym; - - for (syn = synonyms; syn; syn = syn->next) - { - if (!(syn->context & context)) continue; - for (synonym = syn->firstsynonym->next; synonym; synonym = synonym->next) - { - StringReplaceWords(string, synonym->string, syn->firstsynonym->string); - } //end for - } //end for -} //end of the function BotReplaceSynonyms -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotReplaceWeightedSynonyms(char *string, unsigned long int context) -{ - bot_synonymlist_t *syn; - bot_synonym_t *synonym, *replacement; - float weight, curweight; - - for (syn = synonyms; syn; syn = syn->next) - { - if (!(syn->context & context)) continue; - //choose a weighted random replacement synonym - weight = random() * syn->totalweight; - if (!weight) continue; - curweight = 0; - for (replacement = syn->firstsynonym; replacement; replacement = replacement->next) - { - curweight += replacement->weight; - if (weight < curweight) break; - } //end for - if (!replacement) continue; - //replace all synonyms with the replacement - for (synonym = syn->firstsynonym; synonym; synonym = synonym->next) - { - if (synonym == replacement) continue; - StringReplaceWords(string, synonym->string, replacement->string); - } //end for - } //end for -} //end of the function BotReplaceWeightedSynonyms -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotReplaceReplySynonyms(char *string, unsigned long int context) -{ - char *str1, *str2, *replacement; - bot_synonymlist_t *syn; - bot_synonym_t *synonym; - - for (str1 = string; *str1; ) - { - //go to the start of the next word - while(*str1 && *str1 <= ' ') str1++; - if (!*str1) break; - // - for (syn = synonyms; syn; syn = syn->next) - { - if (!(syn->context & context)) continue; - for (synonym = syn->firstsynonym->next; synonym; synonym = synonym->next) - { - str2 = synonym->string; - //if the synonym is not at the front of the string continue - str2 = StringContainsWord(str1, synonym->string, qfalse); - if (!str2 || str2 != str1) continue; - // - replacement = syn->firstsynonym->string; - //if the replacement IS in front of the string continue - str2 = StringContainsWord(str1, replacement, qfalse); - if (str2 && str2 == str1) continue; - // - memmove(str1 + strlen(replacement), str1+strlen(synonym->string), - strlen(str1+strlen(synonym->string)) + 1); - //append the synonum replacement - Com_Memcpy(str1, replacement, strlen(replacement)); - // - break; - } //end for - //if a synonym has been replaced - if (synonym) break; - } //end for - //skip over this word - while(*str1 && *str1 > ' ') str1++; - if (!*str1) break; - } //end while -} //end of the function BotReplaceReplySynonyms -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotLoadChatMessage(source_t *source, char *chatmessagestring) -{ - char *ptr; - token_t token; - - ptr = chatmessagestring; - *ptr = 0; - // - while(1) - { - if (!PC_ExpectAnyToken(source, &token)) return qfalse; - //fixed string - if (token.type == TT_STRING) - { - StripDoubleQuotes(token.string); - if (strlen(ptr) + strlen(token.string) + 1 > MAX_MESSAGE_SIZE) - { - SourceError(source, "chat message too long\n"); - return qfalse; - } //end if - strcat(ptr, token.string); - } //end else if - //variable string - else if (token.type == TT_NUMBER && (token.subtype & TT_INTEGER)) - { - if (strlen(ptr) + 7 > MAX_MESSAGE_SIZE) - { - SourceError(source, "chat message too long\n"); - return qfalse; - } //end if - sprintf(&ptr[strlen(ptr)], "%cv%ld%c", ESCAPE_CHAR, token.intvalue, ESCAPE_CHAR); - } //end if - //random string - else if (token.type == TT_NAME) - { - if (strlen(ptr) + 7 > MAX_MESSAGE_SIZE) - { - SourceError(source, "chat message too long\n"); - return qfalse; - } //end if - sprintf(&ptr[strlen(ptr)], "%cr%s%c", ESCAPE_CHAR, token.string, ESCAPE_CHAR); - } //end else if - else - { - SourceError(source, "unknown message component %s\n", token.string); - return qfalse; - } //end else - if (PC_CheckTokenString(source, ";")) break; - if (!PC_ExpectTokenString(source, ",")) return qfalse; - } //end while - // - return qtrue; -} //end of the function BotLoadChatMessage -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotDumpRandomStringList(bot_randomlist_t *randomlist) -{ - FILE *fp; - bot_randomlist_t *random; - bot_randomstring_t *rs; - - fp = Log_FilePointer(); - if (!fp) return; - for (random = randomlist; random; random = random->next) - { - fprintf(fp, "%s = {", random->string); - for (rs = random->firstrandomstring; rs; rs = rs->next) - { - fprintf(fp, "\"%s\"", rs->string); - if (rs->next) fprintf(fp, ", "); - else fprintf(fp, "}\n"); - } //end for - } //end for -} //end of the function BotDumpRandomStringList -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_randomlist_t *BotLoadRandomStrings(char *filename) -{ - int pass, size; - char *ptr = NULL, chatmessagestring[MAX_MESSAGE_SIZE]; - source_t *source; - token_t token; - bot_randomlist_t *randomlist, *lastrandom, *random; - bot_randomstring_t *randomstring; - -#ifdef DEBUG - int starttime = Sys_MilliSeconds(); -#endif //DEBUG - - size = 0; - randomlist = NULL; - random = NULL; - //the synonyms are parsed in two phases - for (pass = 0; pass < 2; pass++) - { - // - if (pass && size) ptr = (char *) GetClearedHunkMemory(size); - // - PC_SetBaseFolder(BOTFILESBASEFOLDER); - source = LoadSourceFile(filename); - if (!source) - { - botimport.Print(PRT_ERROR, "counldn't load %s\n", filename); - return NULL; - } //end if - // - randomlist = NULL; //list - lastrandom = NULL; //last - // - while(PC_ReadToken(source, &token)) - { - size_t len; - if (token.type != TT_NAME) - { - SourceError(source, "unknown random %s", token.string); - FreeSource(source); - return NULL; - } //end if - len = strlen(token.string) + 1; - len = PAD(len, sizeof(long)); - size += sizeof(bot_randomlist_t) + len; - if (pass) - { - random = (bot_randomlist_t *) ptr; - ptr += sizeof(bot_randomlist_t); - random->string = ptr; - ptr += len; - strcpy(random->string, token.string); - random->firstrandomstring = NULL; - random->numstrings = 0; - // - if (lastrandom) lastrandom->next = random; - else randomlist = random; - lastrandom = random; - } //end if - if (!PC_ExpectTokenString(source, "=") || - !PC_ExpectTokenString(source, "{")) - { - FreeSource(source); - return NULL; - } //end if - while(!PC_CheckTokenString(source, "}")) - { - size_t len; - if (!BotLoadChatMessage(source, chatmessagestring)) - { - FreeSource(source); - return NULL; - } //end if - len = strlen(chatmessagestring) + 1; - len = PAD(len, sizeof(long)); - size += sizeof(bot_randomstring_t) + len; - if (pass) - { - randomstring = (bot_randomstring_t *) ptr; - ptr += sizeof(bot_randomstring_t); - randomstring->string = ptr; - ptr += len; - strcpy(randomstring->string, chatmessagestring); - // - random->numstrings++; - randomstring->next = random->firstrandomstring; - random->firstrandomstring = randomstring; - } //end if - } //end while - } //end while - //free the source after one pass - FreeSource(source); - } //end for - botimport.Print(PRT_MESSAGE, "loaded %s\n", filename); - // -#ifdef DEBUG - botimport.Print(PRT_MESSAGE, "random strings %d msec\n", Sys_MilliSeconds() - starttime); - //BotDumpRandomStringList(randomlist); -#endif //DEBUG - // - return randomlist; -} //end of the function BotLoadRandomStrings -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -char *RandomString(char *name) -{ - bot_randomlist_t *random; - bot_randomstring_t *rs; - int i; - - for (random = randomstrings; random; random = random->next) - { - if (!strcmp(random->string, name)) - { - i = random() * random->numstrings; - for (rs = random->firstrandomstring; rs; rs = rs->next) - { - if (--i < 0) break; - } //end for - if (rs) - { - return rs->string; - } //end if - } //end for - } //end for - return NULL; -} //end of the function RandomString -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotDumpMatchTemplates(bot_matchtemplate_t *matches) -{ - FILE *fp; - bot_matchtemplate_t *mt; - bot_matchpiece_t *mp; - bot_matchstring_t *ms; - - fp = Log_FilePointer(); - if (!fp) return; - for (mt = matches; mt; mt = mt->next) - { - fprintf(fp, "{ " ); - for (mp = mt->first; mp; mp = mp->next) - { - if (mp->type == MT_STRING) - { - for (ms = mp->firststring; ms; ms = ms->next) - { - fprintf(fp, "\"%s\"", ms->string); - if (ms->next) fprintf(fp, "|"); - } //end for - } //end if - else if (mp->type == MT_VARIABLE) - { - fprintf(fp, "%d", mp->variable); - } //end else if - if (mp->next) fprintf(fp, ", "); - } //end for - fprintf(fp, " = (%d, %d);}\n", mt->type, mt->subtype); - } //end for -} //end of the function BotDumpMatchTemplates -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotFreeMatchPieces(bot_matchpiece_t *matchpieces) -{ - bot_matchpiece_t *mp, *nextmp; - bot_matchstring_t *ms, *nextms; - - for (mp = matchpieces; mp; mp = nextmp) - { - nextmp = mp->next; - if (mp->type == MT_STRING) - { - for (ms = mp->firststring; ms; ms = nextms) - { - nextms = ms->next; - FreeMemory(ms); - } //end for - } //end if - FreeMemory(mp); - } //end for -} //end of the function BotFreeMatchPieces -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_matchpiece_t *BotLoadMatchPieces(source_t *source, char *endtoken) -{ - int lastwasvariable, emptystring; - token_t token; - bot_matchpiece_t *matchpiece, *firstpiece, *lastpiece; - bot_matchstring_t *matchstring, *lastmatchstring; - - firstpiece = NULL; - lastpiece = NULL; - // - lastwasvariable = qfalse; - // - while(PC_ReadToken(source, &token)) - { - if (token.type == TT_NUMBER && (token.subtype & TT_INTEGER)) - { - if (token.intvalue < 0 || token.intvalue >= MAX_MATCHVARIABLES) - { - SourceError(source, "can't have more than %d match variables\n", MAX_MATCHVARIABLES); - FreeSource(source); - BotFreeMatchPieces(firstpiece); - return NULL; - } //end if - if (lastwasvariable) - { - SourceError(source, "not allowed to have adjacent variables\n"); - FreeSource(source); - BotFreeMatchPieces(firstpiece); - return NULL; - } //end if - lastwasvariable = qtrue; - // - matchpiece = (bot_matchpiece_t *) GetClearedHunkMemory(sizeof(bot_matchpiece_t)); - matchpiece->type = MT_VARIABLE; - matchpiece->variable = token.intvalue; - matchpiece->next = NULL; - if (lastpiece) lastpiece->next = matchpiece; - else firstpiece = matchpiece; - lastpiece = matchpiece; - } //end if - else if (token.type == TT_STRING) - { - // - matchpiece = (bot_matchpiece_t *) GetClearedHunkMemory(sizeof(bot_matchpiece_t)); - matchpiece->firststring = NULL; - matchpiece->type = MT_STRING; - matchpiece->variable = 0; - matchpiece->next = NULL; - if (lastpiece) lastpiece->next = matchpiece; - else firstpiece = matchpiece; - lastpiece = matchpiece; - // - lastmatchstring = NULL; - emptystring = qfalse; - // - do - { - if (matchpiece->firststring) - { - if (!PC_ExpectTokenType(source, TT_STRING, 0, &token)) - { - FreeSource(source); - BotFreeMatchPieces(firstpiece); - return NULL; - } //end if - } //end if - StripDoubleQuotes(token.string); - matchstring = (bot_matchstring_t *) GetClearedHunkMemory(sizeof(bot_matchstring_t) + strlen(token.string) + 1); - matchstring->string = (char *) matchstring + sizeof(bot_matchstring_t); - strcpy(matchstring->string, token.string); - if (!strlen(token.string)) emptystring = qtrue; - matchstring->next = NULL; - if (lastmatchstring) lastmatchstring->next = matchstring; - else matchpiece->firststring = matchstring; - lastmatchstring = matchstring; - } while(PC_CheckTokenString(source, "|")); - //if there was no empty string found - if (!emptystring) lastwasvariable = qfalse; - } //end if - else - { - SourceError(source, "invalid token %s\n", token.string); - FreeSource(source); - BotFreeMatchPieces(firstpiece); - return NULL; - } //end else - if (PC_CheckTokenString(source, endtoken)) break; - if (!PC_ExpectTokenString(source, ",")) - { - FreeSource(source); - BotFreeMatchPieces(firstpiece); - return NULL; - } //end if - } //end while - return firstpiece; -} //end of the function BotLoadMatchPieces -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotFreeMatchTemplates(bot_matchtemplate_t *mt) -{ - bot_matchtemplate_t *nextmt; - - for (; mt; mt = nextmt) - { - nextmt = mt->next; - BotFreeMatchPieces(mt->first); - FreeMemory(mt); - } //end for -} //end of the function BotFreeMatchTemplates -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_matchtemplate_t *BotLoadMatchTemplates(char *matchfile) -{ - source_t *source; - token_t token; - bot_matchtemplate_t *matchtemplate, *matches, *lastmatch; - unsigned long int context; - - PC_SetBaseFolder(BOTFILESBASEFOLDER); - source = LoadSourceFile(matchfile); - if (!source) - { - botimport.Print(PRT_ERROR, "counldn't load %s\n", matchfile); - return NULL; - } //end if - // - matches = NULL; //list with matches - lastmatch = NULL; //last match in the list - - while(PC_ReadToken(source, &token)) - { - if (token.type != TT_NUMBER || !(token.subtype & TT_INTEGER)) - { - SourceError(source, "expected integer, found %s\n", token.string); - BotFreeMatchTemplates(matches); - FreeSource(source); - return NULL; - } //end if - //the context - context = token.intvalue; - // - if (!PC_ExpectTokenString(source, "{")) - { - BotFreeMatchTemplates(matches); - FreeSource(source); - return NULL; - } //end if - // - while(PC_ReadToken(source, &token)) - { - if (!strcmp(token.string, "}")) break; - // - PC_UnreadLastToken(source); - // - matchtemplate = (bot_matchtemplate_t *) GetClearedHunkMemory(sizeof(bot_matchtemplate_t)); - matchtemplate->context = context; - matchtemplate->next = NULL; - //add the match template to the list - if (lastmatch) lastmatch->next = matchtemplate; - else matches = matchtemplate; - lastmatch = matchtemplate; - //load the match template - matchtemplate->first = BotLoadMatchPieces(source, "="); - if (!matchtemplate->first) - { - BotFreeMatchTemplates(matches); - return NULL; - } //end if - //read the match type - if (!PC_ExpectTokenString(source, "(") || - !PC_ExpectTokenType(source, TT_NUMBER, TT_INTEGER, &token)) - { - BotFreeMatchTemplates(matches); - FreeSource(source); - return NULL; - } //end if - matchtemplate->type = token.intvalue; - //read the match subtype - if (!PC_ExpectTokenString(source, ",") || - !PC_ExpectTokenType(source, TT_NUMBER, TT_INTEGER, &token)) - { - BotFreeMatchTemplates(matches); - FreeSource(source); - return NULL; - } //end if - matchtemplate->subtype = token.intvalue; - //read trailing punctuations - if (!PC_ExpectTokenString(source, ")") || - !PC_ExpectTokenString(source, ";")) - { - BotFreeMatchTemplates(matches); - FreeSource(source); - return NULL; - } //end if - } //end while - } //end while - //free the source - FreeSource(source); - botimport.Print(PRT_MESSAGE, "loaded %s\n", matchfile); - // - //BotDumpMatchTemplates(matches); - // - return matches; -} //end of the function BotLoadMatchTemplates -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int StringsMatch(bot_matchpiece_t *pieces, bot_match_t *match) -{ - int lastvariable, index; - char *strptr, *newstrptr; - bot_matchpiece_t *mp; - bot_matchstring_t *ms; - - //no last variable - lastvariable = -1; - //pointer to the string to compare the match string with - strptr = match->string; - //Log_Write("match: %s", strptr); - //compare the string with the current match string - for (mp = pieces; mp; mp = mp->next) - { - //if it is a piece of string - if (mp->type == MT_STRING) - { - newstrptr = NULL; - for (ms = mp->firststring; ms; ms = ms->next) - { - if (!strlen(ms->string)) - { - newstrptr = strptr; - break; - } //end if - //Log_Write("MT_STRING: %s", mp->string); - index = StringContains(strptr, ms->string, qfalse); - if (index >= 0) - { - newstrptr = strptr + index; - if (lastvariable >= 0) - { - match->variables[lastvariable].length = - (newstrptr - match->string) - match->variables[lastvariable].offset; - //newstrptr - match->variables[lastvariable].ptr; - lastvariable = -1; - break; - } //end if - else if (index == 0) - { - break; - } //end else - newstrptr = NULL; - } //end if - } //end for - if (!newstrptr) return qfalse; - strptr = newstrptr + strlen(ms->string); - } //end if - //if it is a variable piece of string - else if (mp->type == MT_VARIABLE) - { - //Log_Write("MT_VARIABLE"); - match->variables[mp->variable].offset = strptr - match->string; - lastvariable = mp->variable; - } //end else if - } //end for - //if a match was found - if (!mp && (lastvariable >= 0 || !strlen(strptr))) - { - //if the last piece was a variable string - if (lastvariable >= 0) - { - assert( match->variables[lastvariable].offset >= 0 ); // bk001204 - match->variables[lastvariable].length = - strlen(&match->string[ (int) match->variables[lastvariable].offset]); - } //end if - return qtrue; - } //end if - return qfalse; -} //end of the function StringsMatch -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotFindMatch(char *str, bot_match_t *match, unsigned long int context) -{ - int i; - bot_matchtemplate_t *ms; - - strncpy(match->string, str, MAX_MESSAGE_SIZE); - //remove any trailing enters - while(strlen(match->string) && - match->string[strlen(match->string)-1] == '\n') - { - match->string[strlen(match->string)-1] = '\0'; - } //end while - //compare the string with all the match strings - for (ms = matchtemplates; ms; ms = ms->next) - { - if (!(ms->context & context)) continue; - //reset the match variable offsets - for (i = 0; i < MAX_MATCHVARIABLES; i++) match->variables[i].offset = -1; - // - if (StringsMatch(ms->first, match)) - { - match->type = ms->type; - match->subtype = ms->subtype; - return qtrue; - } //end if - } //end for - return qfalse; -} //end of the function BotFindMatch -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotMatchVariable(bot_match_t *match, int variable, char *buf, int size) -{ - if (variable < 0 || variable >= MAX_MATCHVARIABLES) - { - botimport.Print(PRT_FATAL, "BotMatchVariable: variable out of range\n"); - strcpy(buf, ""); - return; - } //end if - - if (match->variables[variable].offset >= 0) - { - if (match->variables[variable].length < size) - size = match->variables[variable].length+1; - assert( match->variables[variable].offset >= 0 ); // bk001204 - strncpy(buf, &match->string[ (int) match->variables[variable].offset], size-1); - buf[size-1] = '\0'; - } //end if - else - { - strcpy(buf, ""); - } //end else - return; -} //end of the function BotMatchVariable -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_stringlist_t *BotFindStringInList(bot_stringlist_t *list, char *string) -{ - bot_stringlist_t *s; - - for (s = list; s; s = s->next) - { - if (!strcmp(s->string, string)) return s; - } //end for - return NULL; -} //end of the function BotFindStringInList -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_stringlist_t *BotCheckChatMessageIntegrety(char *message, bot_stringlist_t *stringlist) -{ - int i; - char *msgptr; - char temp[MAX_MESSAGE_SIZE]; - bot_stringlist_t *s; - - msgptr = message; - // - while(*msgptr) - { - if (*msgptr == ESCAPE_CHAR) - { - msgptr++; - switch(*msgptr) - { - case 'v': //variable - { - //step over the 'v' - msgptr++; - while(*msgptr && *msgptr != ESCAPE_CHAR) msgptr++; - //step over the trailing escape char - if (*msgptr) msgptr++; - break; - } //end case - case 'r': //random - { - //step over the 'r' - msgptr++; - for (i = 0; (*msgptr && *msgptr != ESCAPE_CHAR); i++) - { - temp[i] = *msgptr++; - } //end while - temp[i] = '\0'; - //step over the trailing escape char - if (*msgptr) msgptr++; - //find the random keyword - if (!RandomString(temp)) - { - if (!BotFindStringInList(stringlist, temp)) - { - Log_Write("%s = {\"%s\"} //MISSING RANDOM\r\n", temp, temp); - s = GetClearedMemory(sizeof(bot_stringlist_t) + strlen(temp) + 1); - s->string = (char *) s + sizeof(bot_stringlist_t); - strcpy(s->string, temp); - s->next = stringlist; - stringlist = s; - } //end if - } //end if - break; - } //end case - default: - { - botimport.Print(PRT_FATAL, "BotCheckChatMessageIntegrety: message \"%s\" invalid escape char\n", message); - break; - } //end default - } //end switch - } //end if - else - { - msgptr++; - } //end else - } //end while - return stringlist; -} //end of the function BotCheckChatMessageIntegrety -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotCheckInitialChatIntegrety(bot_chat_t *chat) -{ - bot_chattype_t *t; - bot_chatmessage_t *cm; - bot_stringlist_t *stringlist, *s, *nexts; - - stringlist = NULL; - for (t = chat->types; t; t = t->next) - { - for (cm = t->firstchatmessage; cm; cm = cm->next) - { - stringlist = BotCheckChatMessageIntegrety(cm->chatmessage, stringlist); - } //end for - } //end for - for (s = stringlist; s; s = nexts) - { - nexts = s->next; - FreeMemory(s); - } //end for -} //end of the function BotCheckInitialChatIntegrety -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotCheckReplyChatIntegrety(bot_replychat_t *replychat) -{ - bot_replychat_t *rp; - bot_chatmessage_t *cm; - bot_stringlist_t *stringlist, *s, *nexts; - - stringlist = NULL; - for (rp = replychat; rp; rp = rp->next) - { - for (cm = rp->firstchatmessage; cm; cm = cm->next) - { - stringlist = BotCheckChatMessageIntegrety(cm->chatmessage, stringlist); - } //end for - } //end for - for (s = stringlist; s; s = nexts) - { - nexts = s->next; - FreeMemory(s); - } //end for -} //end of the function BotCheckReplyChatIntegrety -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotDumpReplyChat(bot_replychat_t *replychat) -{ - FILE *fp; - bot_replychat_t *rp; - bot_replychatkey_t *key; - bot_chatmessage_t *cm; - bot_matchpiece_t *mp; - - fp = Log_FilePointer(); - if (!fp) return; - fprintf(fp, "BotDumpReplyChat:\n"); - for (rp = replychat; rp; rp = rp->next) - { - fprintf(fp, "["); - for (key = rp->keys; key; key = key->next) - { - if (key->flags & RCKFL_AND) fprintf(fp, "&"); - else if (key->flags & RCKFL_NOT) fprintf(fp, "!"); - // - if (key->flags & RCKFL_NAME) fprintf(fp, "name"); - else if (key->flags & RCKFL_GENDERFEMALE) fprintf(fp, "female"); - else if (key->flags & RCKFL_GENDERMALE) fprintf(fp, "male"); - else if (key->flags & RCKFL_GENDERLESS) fprintf(fp, "it"); - else if (key->flags & RCKFL_VARIABLES) - { - fprintf(fp, "("); - for (mp = key->match; mp; mp = mp->next) - { - if (mp->type == MT_STRING) fprintf(fp, "\"%s\"", mp->firststring->string); - else fprintf(fp, "%d", mp->variable); - if (mp->next) fprintf(fp, ", "); - } //end for - fprintf(fp, ")"); - } //end if - else if (key->flags & RCKFL_STRING) - { - fprintf(fp, "\"%s\"", key->string); - } //end if - if (key->next) fprintf(fp, ", "); - else fprintf(fp, "] = %1.0f\n", rp->priority); - } //end for - fprintf(fp, "{\n"); - for (cm = rp->firstchatmessage; cm; cm = cm->next) - { - fprintf(fp, "\t\"%s\";\n", cm->chatmessage); - } //end for - fprintf(fp, "}\n"); - } //end for -} //end of the function BotDumpReplyChat -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotFreeReplyChat(bot_replychat_t *replychat) -{ - bot_replychat_t *rp, *nextrp; - bot_replychatkey_t *key, *nextkey; - bot_chatmessage_t *cm, *nextcm; - - for (rp = replychat; rp; rp = nextrp) - { - nextrp = rp->next; - for (key = rp->keys; key; key = nextkey) - { - nextkey = key->next; - if (key->match) BotFreeMatchPieces(key->match); - if (key->string) FreeMemory(key->string); - FreeMemory(key); - } //end for - for (cm = rp->firstchatmessage; cm; cm = nextcm) - { - nextcm = cm->next; - FreeMemory(cm); - } //end for - FreeMemory(rp); - } //end for -} //end of the function BotFreeReplyChat -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotCheckValidReplyChatKeySet(source_t *source, bot_replychatkey_t *keys) -{ - int allprefixed, hasvariableskey, hasstringkey; - bot_matchpiece_t *m; - bot_matchstring_t *ms; - bot_replychatkey_t *key, *key2; - - // - allprefixed = qtrue; - hasvariableskey = hasstringkey = qfalse; - for (key = keys; key; key = key->next) - { - if (!(key->flags & (RCKFL_AND|RCKFL_NOT))) - { - allprefixed = qfalse; - if (key->flags & RCKFL_VARIABLES) - { - for (m = key->match; m; m = m->next) - { - if (m->type == MT_VARIABLE) hasvariableskey = qtrue; - } //end for - } //end if - else if (key->flags & RCKFL_STRING) - { - hasstringkey = qtrue; - } //end else if - } //end if - else if ((key->flags & RCKFL_AND) && (key->flags & RCKFL_STRING)) - { - for (key2 = keys; key2; key2 = key2->next) - { - if (key2 == key) continue; - if (key2->flags & RCKFL_NOT) continue; - if (key2->flags & RCKFL_VARIABLES) - { - for (m = key2->match; m; m = m->next) - { - if (m->type == MT_STRING) - { - for (ms = m->firststring; ms; ms = ms->next) - { - if (StringContains(ms->string, key->string, qfalse) != -1) - { - break; - } //end if - } //end for - if (ms) break; - } //end if - else if (m->type == MT_VARIABLE) - { - break; - } //end if - } //end for - if (!m) - { - SourceWarning(source, "one of the match templates does not " - "leave space for the key %s with the & prefix", key->string); - } //end if - } //end if - } //end for - } //end else - if ((key->flags & RCKFL_NOT) && (key->flags & RCKFL_STRING)) - { - for (key2 = keys; key2; key2 = key2->next) - { - if (key2 == key) continue; - if (key2->flags & RCKFL_NOT) continue; - if (key2->flags & RCKFL_STRING) - { - if (StringContains(key2->string, key->string, qfalse) != -1) - { - SourceWarning(source, "the key %s with prefix ! is inside the key %s", key->string, key2->string); - } //end if - } //end if - else if (key2->flags & RCKFL_VARIABLES) - { - for (m = key2->match; m; m = m->next) - { - if (m->type == MT_STRING) - { - for (ms = m->firststring; ms; ms = ms->next) - { - if (StringContains(ms->string, key->string, qfalse) != -1) - { - SourceWarning(source, "the key %s with prefix ! is inside " - "the match template string %s", key->string, ms->string); - } //end if - } //end for - } //end if - } //end for - } //end else if - } //end for - } //end if - } //end for - if (allprefixed) SourceWarning(source, "all keys have a & or ! prefix"); - if (hasvariableskey && hasstringkey) - { - SourceWarning(source, "variables from the match template(s) could be " - "invalid when outputting one of the chat messages"); - } //end if -} //end of the function BotCheckValidReplyChatKeySet -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_replychat_t *BotLoadReplyChat(char *filename) -{ - char chatmessagestring[MAX_MESSAGE_SIZE]; - char namebuffer[MAX_MESSAGE_SIZE]; - source_t *source; - token_t token; - bot_chatmessage_t *chatmessage = NULL; - bot_replychat_t *replychat, *replychatlist; - bot_replychatkey_t *key; - - PC_SetBaseFolder(BOTFILESBASEFOLDER); - source = LoadSourceFile(filename); - if (!source) - { - botimport.Print(PRT_ERROR, "counldn't load %s\n", filename); - return NULL; - } //end if - // - replychatlist = NULL; - // - while(PC_ReadToken(source, &token)) - { - if (strcmp(token.string, "[")) - { - SourceError(source, "expected [, found %s", token.string); - BotFreeReplyChat(replychatlist); - FreeSource(source); - return NULL; - } //end if - // - replychat = GetClearedHunkMemory(sizeof(bot_replychat_t)); - replychat->keys = NULL; - replychat->next = replychatlist; - replychatlist = replychat; - //read the keys, there must be at least one key - do - { - //allocate a key - key = (bot_replychatkey_t *) GetClearedHunkMemory(sizeof(bot_replychatkey_t)); - key->flags = 0; - key->string = NULL; - key->match = NULL; - key->next = replychat->keys; - replychat->keys = key; - //check for MUST BE PRESENT and MUST BE ABSENT keys - if (PC_CheckTokenString(source, "&")) key->flags |= RCKFL_AND; - else if (PC_CheckTokenString(source, "!")) key->flags |= RCKFL_NOT; - //special keys - if (PC_CheckTokenString(source, "name")) key->flags |= RCKFL_NAME; - else if (PC_CheckTokenString(source, "female")) key->flags |= RCKFL_GENDERFEMALE; - else if (PC_CheckTokenString(source, "male")) key->flags |= RCKFL_GENDERMALE; - else if (PC_CheckTokenString(source, "it")) key->flags |= RCKFL_GENDERLESS; - else if (PC_CheckTokenString(source, "(")) //match key - { - key->flags |= RCKFL_VARIABLES; - key->match = BotLoadMatchPieces(source, ")"); - if (!key->match) - { - BotFreeReplyChat(replychatlist); - return NULL; - } //end if - } //end else if - else if (PC_CheckTokenString(source, "<")) //bot names - { - key->flags |= RCKFL_BOTNAMES; - strcpy(namebuffer, ""); - do - { - if (!PC_ExpectTokenType(source, TT_STRING, 0, &token)) - { - BotFreeReplyChat(replychatlist); - FreeSource(source); - return NULL; - } //end if - StripDoubleQuotes(token.string); - if (strlen(namebuffer)) strcat(namebuffer, "\\"); - strcat(namebuffer, token.string); - } while(PC_CheckTokenString(source, ",")); - if (!PC_ExpectTokenString(source, ">")) - { - BotFreeReplyChat(replychatlist); - FreeSource(source); - return NULL; - } //end if - key->string = (char *) GetClearedHunkMemory(strlen(namebuffer) + 1); - strcpy(key->string, namebuffer); - } //end else if - else //normal string key - { - key->flags |= RCKFL_STRING; - if (!PC_ExpectTokenType(source, TT_STRING, 0, &token)) - { - BotFreeReplyChat(replychatlist); - FreeSource(source); - return NULL; - } //end if - StripDoubleQuotes(token.string); - key->string = (char *) GetClearedHunkMemory(strlen(token.string) + 1); - strcpy(key->string, token.string); - } //end else - // - PC_CheckTokenString(source, ","); - } while(!PC_CheckTokenString(source, "]")); - // - BotCheckValidReplyChatKeySet(source, replychat->keys); - //read the = sign and the priority - if (!PC_ExpectTokenString(source, "=") || - !PC_ExpectTokenType(source, TT_NUMBER, 0, &token)) - { - BotFreeReplyChat(replychatlist); - FreeSource(source); - return NULL; - } //end if - replychat->priority = token.floatvalue; - //read the leading { - if (!PC_ExpectTokenString(source, "{")) - { - BotFreeReplyChat(replychatlist); - FreeSource(source); - return NULL; - } //end if - replychat->numchatmessages = 0; - //while the trailing } is not found - while(!PC_CheckTokenString(source, "}")) - { - if (!BotLoadChatMessage(source, chatmessagestring)) - { - BotFreeReplyChat(replychatlist); - FreeSource(source); - return NULL; - } //end if - chatmessage = (bot_chatmessage_t *) GetClearedHunkMemory(sizeof(bot_chatmessage_t) + strlen(chatmessagestring) + 1); - chatmessage->chatmessage = (char *) chatmessage + sizeof(bot_chatmessage_t); - strcpy(chatmessage->chatmessage, chatmessagestring); - chatmessage->time = -2*CHATMESSAGE_RECENTTIME; - chatmessage->next = replychat->firstchatmessage; - //add the chat message to the reply chat - replychat->firstchatmessage = chatmessage; - replychat->numchatmessages++; - } //end while - } //end while - FreeSource(source); - botimport.Print(PRT_MESSAGE, "loaded %s\n", filename); - // - //BotDumpReplyChat(replychatlist); - if (bot_developer) - { - BotCheckReplyChatIntegrety(replychatlist); - } //end if - // - if (!replychatlist) botimport.Print(PRT_MESSAGE, "no rchats\n"); - // - return replychatlist; -} //end of the function BotLoadReplyChat -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotDumpInitialChat(bot_chat_t *chat) -{ - bot_chattype_t *t; - bot_chatmessage_t *m; - - Log_Write("{"); - for (t = chat->types; t; t = t->next) - { - Log_Write(" type \"%s\"", t->name); - Log_Write(" {"); - Log_Write(" numchatmessages = %d", t->numchatmessages); - for (m = t->firstchatmessage; m; m = m->next) - { - Log_Write(" \"%s\"", m->chatmessage); - } //end for - Log_Write(" }"); - } //end for - Log_Write("}"); -} //end of the function BotDumpInitialChat -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_chat_t *BotLoadInitialChat(char *chatfile, char *chatname) -{ - int pass, foundchat, indent, size; - char *ptr = NULL; - char chatmessagestring[MAX_MESSAGE_SIZE]; - source_t *source; - token_t token; - bot_chat_t *chat = NULL; - bot_chattype_t *chattype = NULL; - bot_chatmessage_t *chatmessage = NULL; -#ifdef DEBUG - int starttime; - - starttime = Sys_MilliSeconds(); -#endif //DEBUG - // - size = 0; - foundchat = qfalse; - //a bot chat is parsed in two phases - for (pass = 0; pass < 2; pass++) - { - //allocate memory - if (pass && size) ptr = (char *) GetClearedMemory(size); - //load the source file - PC_SetBaseFolder(BOTFILESBASEFOLDER); - source = LoadSourceFile(chatfile); - if (!source) - { - botimport.Print(PRT_ERROR, "counldn't load %s\n", chatfile); - return NULL; - } //end if - //chat structure - if (pass) - { - chat = (bot_chat_t *) ptr; - ptr += sizeof(bot_chat_t); - } //end if - size = sizeof(bot_chat_t); - // - while(PC_ReadToken(source, &token)) - { - if (!strcmp(token.string, "chat")) - { - if (!PC_ExpectTokenType(source, TT_STRING, 0, &token)) - { - FreeSource(source); - return NULL; - } //end if - StripDoubleQuotes(token.string); - //after the chat name we expect a opening brace - if (!PC_ExpectTokenString(source, "{")) - { - FreeSource(source); - return NULL; - } //end if - //if the chat name is found - if (!Q_stricmp(token.string, chatname)) - { - foundchat = qtrue; - //read the chat types - while(1) - { - if (!PC_ExpectAnyToken(source, &token)) - { - FreeSource(source); - return NULL; - } //end if - if (!strcmp(token.string, "}")) break; - if (strcmp(token.string, "type")) - { - SourceError(source, "expected type found %s\n", token.string); - FreeSource(source); - return NULL; - } //end if - //expect the chat type name - if (!PC_ExpectTokenType(source, TT_STRING, 0, &token) || - !PC_ExpectTokenString(source, "{")) - { - FreeSource(source); - return NULL; - } //end if - StripDoubleQuotes(token.string); - if (pass) - { - chattype = (bot_chattype_t *) ptr; - strncpy(chattype->name, token.string, MAX_CHATTYPE_NAME); - chattype->firstchatmessage = NULL; - //add the chat type to the chat - chattype->next = chat->types; - chat->types = chattype; - // - ptr += sizeof(bot_chattype_t); - } //end if - size += sizeof(bot_chattype_t); - //read the chat messages - while(!PC_CheckTokenString(source, "}")) - { - size_t len; - if (!BotLoadChatMessage(source, chatmessagestring)) - { - FreeSource(source); - return NULL; - } //end if - len = strlen(chatmessagestring) + 1; - len = PAD(len, sizeof(long)); - if (pass) - { - chatmessage = (bot_chatmessage_t *) ptr; - chatmessage->time = -2*CHATMESSAGE_RECENTTIME; - //put the chat message in the list - chatmessage->next = chattype->firstchatmessage; - chattype->firstchatmessage = chatmessage; - //store the chat message - ptr += sizeof(bot_chatmessage_t); - chatmessage->chatmessage = ptr; - strcpy(chatmessage->chatmessage, chatmessagestring); - ptr += len; - //the number of chat messages increased - chattype->numchatmessages++; - } //end if - size += sizeof(bot_chatmessage_t) + len; - } //end if - } //end while - } //end if - else //skip the bot chat - { - indent = 1; - while(indent) - { - if (!PC_ExpectAnyToken(source, &token)) - { - FreeSource(source); - return NULL; - } //end if - if (!strcmp(token.string, "{")) indent++; - else if (!strcmp(token.string, "}")) indent--; - } //end while - } //end else - } //end if - else - { - SourceError(source, "unknown definition %s\n", token.string); - FreeSource(source); - return NULL; - } //end else - } //end while - //free the source - FreeSource(source); - //if the requested character is not found - if (!foundchat) - { - botimport.Print(PRT_ERROR, "couldn't find chat %s in %s\n", chatname, chatfile); - return NULL; - } //end if - } //end for - // - botimport.Print(PRT_MESSAGE, "loaded %s from %s\n", chatname, chatfile); - // - //BotDumpInitialChat(chat); - if (bot_developer) - { - BotCheckInitialChatIntegrety(chat); - } //end if -#ifdef DEBUG - botimport.Print(PRT_MESSAGE, "initial chats loaded in %d msec\n", Sys_MilliSeconds() - starttime); -#endif //DEBUG - //character was read succesfully - return chat; -} //end of the function BotLoadInitialChat -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotFreeChatFile(int chatstate) -{ - bot_chatstate_t *cs; - - cs = BotChatStateFromHandle(chatstate); - if (!cs) return; - if (cs->chat) FreeMemory(cs->chat); - cs->chat = NULL; -} //end of the function BotFreeChatFile -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotLoadChatFile(int chatstate, char *chatfile, char *chatname) -{ - bot_chatstate_t *cs; - int n, avail = 0; - - cs = BotChatStateFromHandle(chatstate); - if (!cs) return BLERR_CANNOTLOADICHAT; - BotFreeChatFile(chatstate); - - if (!LibVarGetValue("bot_reloadcharacters")) - { - avail = -1; - for( n = 0; n < MAX_CLIENTS; n++ ) { - if( !ichatdata[n] ) { - if( avail == -1 ) { - avail = n; - } - continue; - } - if( strcmp( chatfile, ichatdata[n]->filename ) != 0 ) { - continue; - } - if( strcmp( chatname, ichatdata[n]->chatname ) != 0 ) { - continue; - } - cs->chat = ichatdata[n]->chat; - // botimport.Print( PRT_MESSAGE, "retained %s from %s\n", chatname, chatfile ); - return BLERR_NOERROR; - } - - if( avail == -1 ) { - botimport.Print(PRT_FATAL, "ichatdata table full; couldn't load chat %s from %s\n", chatname, chatfile); - return BLERR_CANNOTLOADICHAT; - } - } - - cs->chat = BotLoadInitialChat(chatfile, chatname); - if (!cs->chat) - { - botimport.Print(PRT_FATAL, "couldn't load chat %s from %s\n", chatname, chatfile); - return BLERR_CANNOTLOADICHAT; - } //end if - if (!LibVarGetValue("bot_reloadcharacters")) - { - ichatdata[avail] = GetClearedMemory( sizeof(bot_ichatdata_t) ); - ichatdata[avail]->chat = cs->chat; - Q_strncpyz( ichatdata[avail]->chatname, chatname, sizeof(ichatdata[avail]->chatname) ); - Q_strncpyz( ichatdata[avail]->filename, chatfile, sizeof(ichatdata[avail]->filename) ); - } //end if - - return BLERR_NOERROR; -} //end of the function BotLoadChatFile -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotExpandChatMessage(char *outmessage, char *message, unsigned long mcontext, - bot_match_t *match, unsigned long vcontext, int reply) -{ - int num, len, i, expansion; - char *outputbuf, *ptr, *msgptr; - char temp[MAX_MESSAGE_SIZE]; - - expansion = qfalse; - msgptr = message; - outputbuf = outmessage; - len = 0; - // - while(*msgptr) - { - if (*msgptr == ESCAPE_CHAR) - { - msgptr++; - switch(*msgptr) - { - case 'v': //variable - { - msgptr++; - num = 0; - while(*msgptr && *msgptr != ESCAPE_CHAR) - { - num = num * 10 + (*msgptr++) - '0'; - } //end while - //step over the trailing escape char - if (*msgptr) msgptr++; - if (num > MAX_MATCHVARIABLES) - { - botimport.Print(PRT_ERROR, "BotConstructChat: message %s variable %d out of range\n", message, num); - return qfalse; - } //end if - if (match->variables[num].offset >= 0) - { - assert( match->variables[num].offset >= 0 ); // bk001204 - ptr = &match->string[ (int) match->variables[num].offset]; - for (i = 0; i < match->variables[num].length; i++) - { - temp[i] = ptr[i]; - } //end for - temp[i] = 0; - //if it's a reply message - if (reply) - { - //replace the reply synonyms in the variables - BotReplaceReplySynonyms(temp, vcontext); - } //end if - else - { - //replace synonyms in the variable context - BotReplaceSynonyms(temp, vcontext); - } //end else - // - if (len + strlen(temp) >= MAX_MESSAGE_SIZE) - { - botimport.Print(PRT_ERROR, "BotConstructChat: message %s too long\n", message); - return qfalse; - } //end if - strcpy(&outputbuf[len], temp); - len += strlen(temp); - } //end if - break; - } //end case - case 'r': //random - { - msgptr++; - for (i = 0; (*msgptr && *msgptr != ESCAPE_CHAR); i++) - { - temp[i] = *msgptr++; - } //end while - temp[i] = '\0'; - //step over the trailing escape char - if (*msgptr) msgptr++; - //find the random keyword - ptr = RandomString(temp); - if (!ptr) - { - botimport.Print(PRT_ERROR, "BotConstructChat: unknown random string %s\n", temp); - return qfalse; - } //end if - if (len + strlen(ptr) >= MAX_MESSAGE_SIZE) - { - botimport.Print(PRT_ERROR, "BotConstructChat: message \"%s\" too long\n", message); - return qfalse; - } //end if - strcpy(&outputbuf[len], ptr); - len += strlen(ptr); - expansion = qtrue; - break; - } //end case - default: - { - botimport.Print(PRT_FATAL, "BotConstructChat: message \"%s\" invalid escape char\n", message); - break; - } //end default - } //end switch - } //end if - else - { - outputbuf[len++] = *msgptr++; - if (len >= MAX_MESSAGE_SIZE) - { - botimport.Print(PRT_ERROR, "BotConstructChat: message \"%s\" too long\n", message); - break; - } //end if - } //end else - } //end while - outputbuf[len] = '\0'; - //replace synonyms weighted in the message context - BotReplaceWeightedSynonyms(outputbuf, mcontext); - //return true if a random was expanded - return expansion; -} //end of the function BotExpandChatMessage -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotConstructChatMessage(bot_chatstate_t *chatstate, char *message, unsigned long mcontext, - bot_match_t *match, unsigned long vcontext, int reply) -{ - int i; - char srcmessage[MAX_MESSAGE_SIZE]; - - strcpy(srcmessage, message); - for (i = 0; i < 10; i++) - { - if (!BotExpandChatMessage(chatstate->chatmessage, srcmessage, mcontext, match, vcontext, reply)) - { - break; - } //end if - strcpy(srcmessage, chatstate->chatmessage); - } //end for - if (i >= 10) - { - botimport.Print(PRT_WARNING, "too many expansions in chat message\n"); - botimport.Print(PRT_WARNING, "%s\n", chatstate->chatmessage); - } //end if -} //end of the function BotConstructChatMessage -//=========================================================================== -// randomly chooses one of the chat message of the given type -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -char *BotChooseInitialChatMessage(bot_chatstate_t *cs, char *type) -{ - int n, numchatmessages; - float besttime; - bot_chattype_t *t; - bot_chatmessage_t *m, *bestchatmessage; - bot_chat_t *chat; - - chat = cs->chat; - for (t = chat->types; t; t = t->next) - { - if (!Q_stricmp(t->name, type)) - { - numchatmessages = 0; - for (m = t->firstchatmessage; m; m = m->next) - { - if (m->time > AAS_Time()) continue; - numchatmessages++; - } //end if - //if all chat messages have been used recently - if (numchatmessages <= 0) - { - besttime = 0; - bestchatmessage = NULL; - for (m = t->firstchatmessage; m; m = m->next) - { - if (!besttime || m->time < besttime) - { - bestchatmessage = m; - besttime = m->time; - } //end if - } //end for - if (bestchatmessage) return bestchatmessage->chatmessage; - } //end if - else //choose a chat message randomly - { - n = random() * numchatmessages; - for (m = t->firstchatmessage; m; m = m->next) - { - if (m->time > AAS_Time()) continue; - if (--n < 0) - { - m->time = AAS_Time() + CHATMESSAGE_RECENTTIME; - return m->chatmessage; - } //end if - } //end for - } //end else - return NULL; - } //end if - } //end for - return NULL; -} //end of the function BotChooseInitialChatMessage -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotNumInitialChats(int chatstate, char *type) -{ - bot_chatstate_t *cs; - bot_chattype_t *t; - - cs = BotChatStateFromHandle(chatstate); - if (!cs) return 0; - - for (t = cs->chat->types; t; t = t->next) - { - if (!Q_stricmp(t->name, type)) - { - if (LibVarGetValue("bot_testichat")) { - botimport.Print(PRT_MESSAGE, "%s has %d chat lines\n", type, t->numchatmessages); - botimport.Print(PRT_MESSAGE, "-------------------\n"); - } - return t->numchatmessages; - } //end if - } //end for - return 0; -} //end of the function BotNumInitialChats -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotInitialChat(int chatstate, char *type, int mcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7) -{ - char *message; - int index; - bot_match_t match; - bot_chatstate_t *cs; - - cs = BotChatStateFromHandle(chatstate); - if (!cs) return; - //if no chat file is loaded - if (!cs->chat) return; - //choose a chat message randomly of the given type - message = BotChooseInitialChatMessage(cs, type); - //if there's no message of the given type - if (!message) - { -#ifdef DEBUG - botimport.Print(PRT_MESSAGE, "no chat messages of type %s\n", type); -#endif //DEBUG - return; - } //end if - // - Com_Memset(&match, 0, sizeof(match)); - index = 0; - if( var0 ) { - strcat(match.string, var0); - match.variables[0].offset = index; - match.variables[0].length = strlen(var0); - index += strlen(var0); - } - if( var1 ) { - strcat(match.string, var1); - match.variables[1].offset = index; - match.variables[1].length = strlen(var1); - index += strlen(var1); - } - if( var2 ) { - strcat(match.string, var2); - match.variables[2].offset = index; - match.variables[2].length = strlen(var2); - index += strlen(var2); - } - if( var3 ) { - strcat(match.string, var3); - match.variables[3].offset = index; - match.variables[3].length = strlen(var3); - index += strlen(var3); - } - if( var4 ) { - strcat(match.string, var4); - match.variables[4].offset = index; - match.variables[4].length = strlen(var4); - index += strlen(var4); - } - if( var5 ) { - strcat(match.string, var5); - match.variables[5].offset = index; - match.variables[5].length = strlen(var5); - index += strlen(var5); - } - if( var6 ) { - strcat(match.string, var6); - match.variables[6].offset = index; - match.variables[6].length = strlen(var6); - index += strlen(var6); - } - if( var7 ) { - strcat(match.string, var7); - match.variables[7].offset = index; - match.variables[7].length = strlen(var7); - index += strlen(var7); - } - // - BotConstructChatMessage(cs, message, mcontext, &match, 0, qfalse); -} //end of the function BotInitialChat -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotPrintReplyChatKeys(bot_replychat_t *replychat) -{ - bot_replychatkey_t *key; - bot_matchpiece_t *mp; - - botimport.Print(PRT_MESSAGE, "["); - for (key = replychat->keys; key; key = key->next) - { - if (key->flags & RCKFL_AND) botimport.Print(PRT_MESSAGE, "&"); - else if (key->flags & RCKFL_NOT) botimport.Print(PRT_MESSAGE, "!"); - // - if (key->flags & RCKFL_NAME) botimport.Print(PRT_MESSAGE, "name"); - else if (key->flags & RCKFL_GENDERFEMALE) botimport.Print(PRT_MESSAGE, "female"); - else if (key->flags & RCKFL_GENDERMALE) botimport.Print(PRT_MESSAGE, "male"); - else if (key->flags & RCKFL_GENDERLESS) botimport.Print(PRT_MESSAGE, "it"); - else if (key->flags & RCKFL_VARIABLES) - { - botimport.Print(PRT_MESSAGE, "("); - for (mp = key->match; mp; mp = mp->next) - { - if (mp->type == MT_STRING) botimport.Print(PRT_MESSAGE, "\"%s\"", mp->firststring->string); - else botimport.Print(PRT_MESSAGE, "%d", mp->variable); - if (mp->next) botimport.Print(PRT_MESSAGE, ", "); - } //end for - botimport.Print(PRT_MESSAGE, ")"); - } //end if - else if (key->flags & RCKFL_STRING) - { - botimport.Print(PRT_MESSAGE, "\"%s\"", key->string); - } //end if - if (key->next) botimport.Print(PRT_MESSAGE, ", "); - else botimport.Print(PRT_MESSAGE, "] = %1.0f\n", replychat->priority); - } //end for - botimport.Print(PRT_MESSAGE, "{\n"); -} //end of the function BotPrintReplyChatKeys -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotReplyChat(int chatstate, char *message, int mcontext, int vcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7) -{ - bot_replychat_t *rchat, *bestrchat; - bot_replychatkey_t *key; - bot_chatmessage_t *m, *bestchatmessage; - bot_match_t match, bestmatch; - int bestpriority, num, found, res, numchatmessages, index; - bot_chatstate_t *cs; - - cs = BotChatStateFromHandle(chatstate); - if (!cs) return qfalse; - Com_Memset(&match, 0, sizeof(bot_match_t)); - strcpy(match.string, message); - bestpriority = -1; - bestchatmessage = NULL; - bestrchat = NULL; - //go through all the reply chats - for (rchat = replychats; rchat; rchat = rchat->next) - { - found = qfalse; - for (key = rchat->keys; key; key = key->next) - { - res = qfalse; - //get the match result - if (key->flags & RCKFL_NAME) res = (StringContains(message, cs->name, qfalse) != -1); - else if (key->flags & RCKFL_BOTNAMES) res = (StringContains(key->string, cs->name, qfalse) != -1); - else if (key->flags & RCKFL_GENDERFEMALE) res = (cs->gender == CHAT_GENDERFEMALE); - else if (key->flags & RCKFL_GENDERMALE) res = (cs->gender == CHAT_GENDERMALE); - else if (key->flags & RCKFL_GENDERLESS) res = (cs->gender == CHAT_GENDERLESS); - else if (key->flags & RCKFL_VARIABLES) res = StringsMatch(key->match, &match); - else if (key->flags & RCKFL_STRING) res = (StringContainsWord(message, key->string, qfalse) != NULL); - //if the key must be present - if (key->flags & RCKFL_AND) - { - if (!res) - { - found = qfalse; - break; - } //end if - } //end else if - //if the key must be absent - else if (key->flags & RCKFL_NOT) - { - if (res) - { - found = qfalse; - break; - } //end if - } //end if - else if (res) - { - found = qtrue; - } //end else - } //end for - // - if (found) - { - if (rchat->priority > bestpriority) - { - numchatmessages = 0; - for (m = rchat->firstchatmessage; m; m = m->next) - { - if (m->time > AAS_Time()) continue; - numchatmessages++; - } //end if - num = random() * numchatmessages; - for (m = rchat->firstchatmessage; m; m = m->next) - { - if (--num < 0) break; - if (m->time > AAS_Time()) continue; - } //end for - //if the reply chat has a message - if (m) - { - Com_Memcpy(&bestmatch, &match, sizeof(bot_match_t)); - bestchatmessage = m; - bestrchat = rchat; - bestpriority = rchat->priority; - } //end if - } //end if - } //end if - } //end for - if (bestchatmessage) - { - index = strlen(bestmatch.string); - if( var0 ) { - strcat(bestmatch.string, var0); - bestmatch.variables[0].offset = index; - bestmatch.variables[0].length = strlen(var0); - index += strlen(var0); - } - if( var1 ) { - strcat(bestmatch.string, var1); - bestmatch.variables[1].offset = index; - bestmatch.variables[1].length = strlen(var1); - index += strlen(var1); - } - if( var2 ) { - strcat(bestmatch.string, var2); - bestmatch.variables[2].offset = index; - bestmatch.variables[2].length = strlen(var2); - index += strlen(var2); - } - if( var3 ) { - strcat(bestmatch.string, var3); - bestmatch.variables[3].offset = index; - bestmatch.variables[3].length = strlen(var3); - index += strlen(var3); - } - if( var4 ) { - strcat(bestmatch.string, var4); - bestmatch.variables[4].offset = index; - bestmatch.variables[4].length = strlen(var4); - index += strlen(var4); - } - if( var5 ) { - strcat(bestmatch.string, var5); - bestmatch.variables[5].offset = index; - bestmatch.variables[5].length = strlen(var5); - index += strlen(var5); - } - if( var6 ) { - strcat(bestmatch.string, var6); - bestmatch.variables[6].offset = index; - bestmatch.variables[6].length = strlen(var6); - index += strlen(var6); - } - if( var7 ) { - strcat(bestmatch.string, var7); - bestmatch.variables[7].offset = index; - bestmatch.variables[7].length = strlen(var7); - index += strlen(var7); - } - if (LibVarGetValue("bot_testrchat")) - { - for (m = bestrchat->firstchatmessage; m; m = m->next) - { - BotConstructChatMessage(cs, m->chatmessage, mcontext, &bestmatch, vcontext, qtrue); - BotRemoveTildes(cs->chatmessage); - botimport.Print(PRT_MESSAGE, "%s\n", cs->chatmessage); - } //end if - } //end if - else - { - bestchatmessage->time = AAS_Time() + CHATMESSAGE_RECENTTIME; - BotConstructChatMessage(cs, bestchatmessage->chatmessage, mcontext, &bestmatch, vcontext, qtrue); - } //end else - return qtrue; - } //end if - return qfalse; -} //end of the function BotReplyChat -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotChatLength(int chatstate) -{ - bot_chatstate_t *cs; - - cs = BotChatStateFromHandle(chatstate); - if (!cs) return 0; - return strlen(cs->chatmessage); -} //end of the function BotChatLength -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotEnterChat(int chatstate, int clientto, int sendto) -{ - bot_chatstate_t *cs; - - cs = BotChatStateFromHandle(chatstate); - if (!cs) return; - - if (strlen(cs->chatmessage)) - { - BotRemoveTildes(cs->chatmessage); - if (LibVarGetValue("bot_testichat")) { - botimport.Print(PRT_MESSAGE, "%s\n", cs->chatmessage); - } - else { - switch(sendto) { - case CHAT_TEAM: - EA_Command(cs->client, va("say_team %s", cs->chatmessage)); - break; - case CHAT_TELL: - EA_Command(cs->client, va("tell %d %s", clientto, cs->chatmessage)); - break; - default: //CHAT_ALL - EA_Command(cs->client, va("say %s", cs->chatmessage)); - break; - } - } - //clear the chat message from the state - strcpy(cs->chatmessage, ""); - } //end if -} //end of the function BotEnterChat -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotGetChatMessage(int chatstate, char *buf, int size) -{ - bot_chatstate_t *cs; - - cs = BotChatStateFromHandle(chatstate); - if (!cs) return; - - BotRemoveTildes(cs->chatmessage); - strncpy(buf, cs->chatmessage, size-1); - buf[size-1] = '\0'; - //clear the chat message from the state - strcpy(cs->chatmessage, ""); -} //end of the function BotGetChatMessage -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotSetChatGender(int chatstate, int gender) -{ - bot_chatstate_t *cs; - - cs = BotChatStateFromHandle(chatstate); - if (!cs) return; - switch(gender) - { - case CHAT_GENDERFEMALE: cs->gender = CHAT_GENDERFEMALE; break; - case CHAT_GENDERMALE: cs->gender = CHAT_GENDERMALE; break; - default: cs->gender = CHAT_GENDERLESS; break; - } //end switch -} //end of the function BotSetChatGender -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotSetChatName(int chatstate, char *name, int client) -{ - bot_chatstate_t *cs; - - cs = BotChatStateFromHandle(chatstate); - if (!cs) return; - cs->client = client; - Com_Memset(cs->name, 0, sizeof(cs->name)); - strncpy(cs->name, name, sizeof(cs->name)); - cs->name[sizeof(cs->name)-1] = '\0'; -} //end of the function BotSetChatName -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotResetChatAI(void) -{ - bot_replychat_t *rchat; - bot_chatmessage_t *m; - - for (rchat = replychats; rchat; rchat = rchat->next) - { - for (m = rchat->firstchatmessage; m; m = m->next) - { - m->time = 0; - } //end for - } //end for -} //end of the function BotResetChatAI -//======================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//======================================================================== -int BotAllocChatState(void) -{ - int i; - - for (i = 1; i <= MAX_CLIENTS; i++) - { - if (!botchatstates[i]) - { - botchatstates[i] = GetClearedMemory(sizeof(bot_chatstate_t)); - return i; - } //end if - } //end for - return 0; -} //end of the function BotAllocChatState -//======================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//======================================================================== -void BotFreeChatState(int handle) -{ - bot_chatstate_t *cs; - bot_consolemessage_t m; - int h; - - if (handle <= 0 || handle > MAX_CLIENTS) - { - botimport.Print(PRT_FATAL, "chat state handle %d out of range\n", handle); - return; - } //end if - if (!botchatstates[handle]) - { - botimport.Print(PRT_FATAL, "invalid chat state %d\n", handle); - return; - } //end if - cs = botchatstates[handle]; - if (LibVarGetValue("bot_reloadcharacters")) - { - BotFreeChatFile(handle); - } //end if - //free all the console messages left in the chat state - for (h = BotNextConsoleMessage(handle, &m); h; h = BotNextConsoleMessage(handle, &m)) - { - //remove the console message - BotRemoveConsoleMessage(handle, h); - } //end for - FreeMemory(botchatstates[handle]); - botchatstates[handle] = NULL; -} //end of the function BotFreeChatState -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotSetupChatAI(void) -{ - char *file; - -#ifdef DEBUG - int starttime = Sys_MilliSeconds(); -#endif //DEBUG - - file = LibVarString("synfile", "syn.c"); - synonyms = BotLoadSynonyms(file); - file = LibVarString("rndfile", "rnd.c"); - randomstrings = BotLoadRandomStrings(file); - file = LibVarString("matchfile", "match.c"); - matchtemplates = BotLoadMatchTemplates(file); - // - if (!LibVarValue("nochat", "0")) - { - file = LibVarString("rchatfile", "rchat.c"); - replychats = BotLoadReplyChat(file); - } //end if - - InitConsoleMessageHeap(); - -#ifdef DEBUG - botimport.Print(PRT_MESSAGE, "setup chat AI %d msec\n", Sys_MilliSeconds() - starttime); -#endif //DEBUG - return BLERR_NOERROR; -} //end of the function BotSetupChatAI -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotShutdownChatAI(void) -{ - int i; - - //free all remaining chat states - for(i = 0; i < MAX_CLIENTS; i++) - { - if (botchatstates[i]) - { - BotFreeChatState(i); - } //end if - } //end for - //free all cached chats - for(i = 0; i < MAX_CLIENTS; i++) - { - if (ichatdata[i]) - { - FreeMemory(ichatdata[i]->chat); - FreeMemory(ichatdata[i]); - ichatdata[i] = NULL; - } //end if - } //end for - if (consolemessageheap) FreeMemory(consolemessageheap); - consolemessageheap = NULL; - if (matchtemplates) BotFreeMatchTemplates(matchtemplates); - matchtemplates = NULL; - if (randomstrings) FreeMemory(randomstrings); - randomstrings = NULL; - if (synonyms) FreeMemory(synonyms); - synonyms = NULL; - if (replychats) BotFreeReplyChat(replychats); - replychats = NULL; -} //end of the function BotShutdownChatAI diff --git a/src/botlib/be_ai_chat.h b/src/botlib/be_ai_chat.h deleted file mode 100644 index dff68101..00000000 --- a/src/botlib/be_ai_chat.h +++ /dev/null @@ -1,114 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// -/***************************************************************************** - * name: be_ai_chat.h - * - * desc: char AI - * - * $Archive: /source/code/botlib/be_ai_chat.h $ - * - *****************************************************************************/ - -#define MAX_MESSAGE_SIZE 256 -#define MAX_CHATTYPE_NAME 32 -#define MAX_MATCHVARIABLES 8 - -#define CHAT_GENDERLESS 0 -#define CHAT_GENDERFEMALE 1 -#define CHAT_GENDERMALE 2 - -#define CHAT_ALL 0 -#define CHAT_TEAM 1 -#define CHAT_TELL 2 - -//a console message -typedef struct bot_consolemessage_s -{ - int handle; - float time; //message time - int type; //message type - char message[MAX_MESSAGE_SIZE]; //message - struct bot_consolemessage_s *prev, *next; //prev and next in list -} bot_consolemessage_t; - -//match variable -typedef struct bot_matchvariable_s -{ - char offset; - int length; -} bot_matchvariable_t; -//returned to AI when a match is found -typedef struct bot_match_s -{ - char string[MAX_MESSAGE_SIZE]; - int type; - int subtype; - bot_matchvariable_t variables[MAX_MATCHVARIABLES]; -} bot_match_t; - -//setup the chat AI -int BotSetupChatAI(void); -//shutdown the chat AI -void BotShutdownChatAI(void); -//returns the handle to a newly allocated chat state -int BotAllocChatState(void); -//frees the chatstate -void BotFreeChatState(int handle); -//adds a console message to the chat state -void BotQueueConsoleMessage(int chatstate, int type, char *message); -//removes the console message from the chat state -void BotRemoveConsoleMessage(int chatstate, int handle); -//returns the next console message from the state -int BotNextConsoleMessage(int chatstate, bot_consolemessage_t *cm); -//returns the number of console messages currently stored in the state -int BotNumConsoleMessages(int chatstate); -//selects a chat message of the given type -void BotInitialChat(int chatstate, char *type, int mcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7); -//returns the number of initial chat messages of the given type -int BotNumInitialChats(int chatstate, char *type); -//find and select a reply for the given message -int BotReplyChat(int chatstate, char *message, int mcontext, int vcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7); -//returns the length of the currently selected chat message -int BotChatLength(int chatstate); -//enters the selected chat message -void BotEnterChat(int chatstate, int clientto, int sendto); -//get the chat message ready to be output -void BotGetChatMessage(int chatstate, char *buf, int size); -//checks if the first string contains the second one, returns index into first string or -1 if not found -int StringContains(char *str1, char *str2, int casesensitive); -//finds a match for the given string using the match templates -int BotFindMatch(char *str, bot_match_t *match, unsigned long int context); -//returns a variable from a match -void BotMatchVariable(bot_match_t *match, int variable, char *buf, int size); -//unify all the white spaces in the string -void UnifyWhiteSpaces(char *string); -//replace all the context related synonyms in the string -void BotReplaceSynonyms(char *string, unsigned long int context); -//loads a chat file for the chat state -int BotLoadChatFile(int chatstate, char *chatfile, char *chatname); -//store the gender of the bot in the chat state -void BotSetChatGender(int chatstate, int gender); -//store the bot name in the chat state -void BotSetChatName(int chatstate, char *name, int client); - diff --git a/src/botlib/be_ai_gen.c b/src/botlib/be_ai_gen.c deleted file mode 100644 index fda4986d..00000000 --- a/src/botlib/be_ai_gen.c +++ /dev/null @@ -1,135 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_ai_gen.c - * - * desc: genetic selection - * - * $Archive: /MissionPack/code/botlib/be_ai_gen.c $ - * - *****************************************************************************/ - -#include "../qcommon/q_shared.h" -#include "l_memory.h" -#include "l_log.h" -#include "l_utils.h" -#include "l_script.h" -#include "l_precomp.h" -#include "l_struct.h" -#include "aasfile.h" -#include "botlib.h" -#include "be_aas.h" -#include "be_aas_funcs.h" -#include "be_interface.h" -#include "be_ai_gen.h" - -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int GeneticSelection(int numranks, float *rankings) -{ - float sum, select; - int i, index; - - sum = 0; - for (i = 0; i < numranks; i++) - { - if (rankings[i] < 0) continue; - sum += rankings[i]; - } //end for - if (sum > 0) - { - //select a bot where the ones with the higest rankings have - //the highest chance of being selected - select = random() * sum; - for (i = 0; i < numranks; i++) - { - if (rankings[i] < 0) continue; - sum -= rankings[i]; - if (sum <= 0) return i; - } //end for - } //end if - //select a bot randomly - index = random() * numranks; - for (i = 0; i < numranks; i++) - { - if (rankings[index] >= 0) return index; - index = (index + 1) % numranks; - } //end for - return 0; -} //end of the function GeneticSelection -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int GeneticParentsAndChildSelection(int numranks, float *ranks, int *parent1, int *parent2, int *child) -{ - float rankings[256], max; - int i; - - if (numranks > 256) - { - botimport.Print(PRT_WARNING, "GeneticParentsAndChildSelection: too many bots\n"); - *parent1 = *parent2 = *child = 0; - return qfalse; - } //end if - for (max = 0, i = 0; i < numranks; i++) - { - if (ranks[i] < 0) continue; - max++; - } //end for - if (max < 3) - { - botimport.Print(PRT_WARNING, "GeneticParentsAndChildSelection: too few valid bots\n"); - *parent1 = *parent2 = *child = 0; - return qfalse; - } //end if - Com_Memcpy(rankings, ranks, sizeof(float) * numranks); - //select first parent - *parent1 = GeneticSelection(numranks, rankings); - rankings[*parent1] = -1; - //select second parent - *parent2 = GeneticSelection(numranks, rankings); - rankings[*parent2] = -1; - //reverse the rankings - max = 0; - for (i = 0; i < numranks; i++) - { - if (rankings[i] < 0) continue; - if (rankings[i] > max) max = rankings[i]; - } //end for - for (i = 0; i < numranks; i++) - { - if (rankings[i] < 0) continue; - rankings[i] = max - rankings[i]; - } //end for - //select child - *child = GeneticSelection(numranks, rankings); - return qtrue; -} //end of the function GeneticParentsAndChildSelection diff --git a/src/botlib/be_ai_gen.h b/src/botlib/be_ai_gen.h deleted file mode 100644 index 41654305..00000000 --- a/src/botlib/be_ai_gen.h +++ /dev/null @@ -1,34 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// - -/***************************************************************************** - * name: be_ai_gen.h - * - * desc: genetic selection - * - * $Archive: /source/code/botlib/be_ai_gen.h $ - * - *****************************************************************************/ - -int GeneticParentsAndChildSelection(int numranks, float *ranks, int *parent1, int *parent2, int *child); diff --git a/src/botlib/be_ai_goal.c b/src/botlib/be_ai_goal.c deleted file mode 100644 index d099080e..00000000 --- a/src/botlib/be_ai_goal.c +++ /dev/null @@ -1,1822 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_ai_goal.c - * - * desc: goal AI - * - * $Archive: /MissionPack/code/botlib/be_ai_goal.c $ - * - *****************************************************************************/ - -#include "../qcommon/q_shared.h" -#include "l_utils.h" -#include "l_libvar.h" -#include "l_memory.h" -#include "l_log.h" -#include "l_script.h" -#include "l_precomp.h" -#include "l_struct.h" -#include "aasfile.h" -#include "botlib.h" -#include "be_aas.h" -#include "be_aas_funcs.h" -#include "be_interface.h" -#include "be_ai_weight.h" -#include "be_ai_goal.h" -#include "be_ai_move.h" - -//#define DEBUG_AI_GOAL -#ifdef RANDOMIZE -#define UNDECIDEDFUZZY -#endif //RANDOMIZE -#define DROPPEDWEIGHT -//minimum avoid goal time -#define AVOID_MINIMUM_TIME 10 -//default avoid goal time -#define AVOID_DEFAULT_TIME 30 -//avoid dropped goal time -#define AVOID_DROPPED_TIME 10 -// -#define TRAVELTIME_SCALE 0.01 -//item flags -#define IFL_NOTFREE 1 //not in free for all -#define IFL_NOTTEAM 2 //not in team play -#define IFL_NOTSINGLE 4 //not in single player -#define IFL_NOTBOT 8 //bot should never go for this -#define IFL_ROAM 16 //bot roam goal - -//location in the map "target_location" -typedef struct maplocation_s -{ - vec3_t origin; - int areanum; - char name[MAX_EPAIRKEY]; - struct maplocation_s *next; -} maplocation_t; - -//camp spots "info_camp" -typedef struct campspot_s -{ - vec3_t origin; - int areanum; - char name[MAX_EPAIRKEY]; - float range; - float weight; - float wait; - float random; - struct campspot_s *next; -} campspot_t; - -//FIXME: these are game specific -typedef enum { - GT_FFA, // free for all - GT_TOURNAMENT, // one on one tournament - GT_SINGLE_PLAYER, // single player tournament - - //-- team games go after this -- - - GT_TEAM, // team deathmatch - GT_CTF, // capture the flag -#ifdef MISSIONPACK - GT_1FCTF, - GT_OBELISK, - GT_HARVESTER, -#endif - GT_MAX_GAME_TYPE -} gametype_t; - -typedef struct levelitem_s -{ - int number; //number of the level item - int iteminfo; //index into the item info - int flags; //item flags - float weight; //fixed roam weight - vec3_t origin; //origin of the item - int goalareanum; //area the item is in - vec3_t goalorigin; //goal origin within the area - int entitynum; //entity number - float timeout; //item is removed after this time - struct levelitem_s *prev, *next; -} levelitem_t; - -typedef struct iteminfo_s -{ - char classname[32]; //classname of the item - char name[MAX_STRINGFIELD]; //name of the item - char model[MAX_STRINGFIELD]; //model of the item - int modelindex; //model index - int type; //item type - int index; //index in the inventory - float respawntime; //respawn time - vec3_t mins; //mins of the item - vec3_t maxs; //maxs of the item - int number; //number of the item info -} iteminfo_t; - -#define ITEMINFO_OFS(x) (int)&(((iteminfo_t *)0)->x) - -fielddef_t iteminfo_fields[] = -{ -{"name", ITEMINFO_OFS(name), FT_STRING}, -{"model", ITEMINFO_OFS(model), FT_STRING}, -{"modelindex", ITEMINFO_OFS(modelindex), FT_INT}, -{"type", ITEMINFO_OFS(type), FT_INT}, -{"index", ITEMINFO_OFS(index), FT_INT}, -{"respawntime", ITEMINFO_OFS(respawntime), FT_FLOAT}, -{"mins", ITEMINFO_OFS(mins), FT_FLOAT|FT_ARRAY, 3}, -{"maxs", ITEMINFO_OFS(maxs), FT_FLOAT|FT_ARRAY, 3}, -{NULL, 0, 0} -}; - -structdef_t iteminfo_struct = -{ - sizeof(iteminfo_t), iteminfo_fields -}; - -typedef struct itemconfig_s -{ - int numiteminfo; - iteminfo_t *iteminfo; -} itemconfig_t; - -//goal state -typedef struct bot_goalstate_s -{ - struct weightconfig_s *itemweightconfig; //weight config - int *itemweightindex; //index from item to weight - // - int client; //client using this goal state - int lastreachabilityarea; //last area with reachabilities the bot was in - // - bot_goal_t goalstack[MAX_GOALSTACK]; //goal stack - int goalstacktop; //the top of the goal stack - // - int avoidgoals[MAX_AVOIDGOALS]; //goals to avoid - float avoidgoaltimes[MAX_AVOIDGOALS]; //times to avoid the goals -} bot_goalstate_t; - -bot_goalstate_t *botgoalstates[MAX_CLIENTS + 1]; // bk001206 - FIXME: init? -//item configuration -itemconfig_t *itemconfig = NULL; // bk001206 - init -//level items -levelitem_t *levelitemheap = NULL; // bk001206 - init -levelitem_t *freelevelitems = NULL; // bk001206 - init -levelitem_t *levelitems = NULL; // bk001206 - init -int numlevelitems = 0; -//map locations -maplocation_t *maplocations = NULL; // bk001206 - init -//camp spots -campspot_t *campspots = NULL; // bk001206 - init -//the game type -int g_gametype = 0; // bk001206 - init -//additional dropped item weight -libvar_t *droppedweight = NULL; // bk001206 - init - -//======================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//======================================================================== -bot_goalstate_t *BotGoalStateFromHandle(int handle) -{ - if (handle <= 0 || handle > MAX_CLIENTS) - { - botimport.Print(PRT_FATAL, "goal state handle %d out of range\n", handle); - return NULL; - } //end if - if (!botgoalstates[handle]) - { - botimport.Print(PRT_FATAL, "invalid goal state %d\n", handle); - return NULL; - } //end if - return botgoalstates[handle]; -} //end of the function BotGoalStateFromHandle -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotInterbreedGoalFuzzyLogic(int parent1, int parent2, int child) -{ - bot_goalstate_t *p1, *p2, *c; - - p1 = BotGoalStateFromHandle(parent1); - p2 = BotGoalStateFromHandle(parent2); - c = BotGoalStateFromHandle(child); - - InterbreedWeightConfigs(p1->itemweightconfig, p2->itemweightconfig, - c->itemweightconfig); -} //end of the function BotInterbreedingGoalFuzzyLogic -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotSaveGoalFuzzyLogic(int goalstate, char *filename) -{ - bot_goalstate_t *gs; - - gs = BotGoalStateFromHandle(goalstate); - - //WriteWeightConfig(filename, gs->itemweightconfig); -} //end of the function BotSaveGoalFuzzyLogic -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotMutateGoalFuzzyLogic(int goalstate, float range) -{ - bot_goalstate_t *gs; - - gs = BotGoalStateFromHandle(goalstate); - - EvolveWeightConfig(gs->itemweightconfig); -} //end of the function BotMutateGoalFuzzyLogic -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -itemconfig_t *LoadItemConfig(char *filename) -{ - int max_iteminfo; - token_t token; - char path[MAX_PATH]; - source_t *source; - itemconfig_t *ic; - iteminfo_t *ii; - - max_iteminfo = (int) LibVarValue("max_iteminfo", "256"); - if (max_iteminfo < 0) - { - botimport.Print(PRT_ERROR, "max_iteminfo = %d\n", max_iteminfo); - max_iteminfo = 256; - LibVarSet( "max_iteminfo", "256" ); - } - - strncpy( path, filename, MAX_PATH ); - PC_SetBaseFolder(BOTFILESBASEFOLDER); - source = LoadSourceFile( path ); - if( !source ) { - botimport.Print( PRT_ERROR, "counldn't load %s\n", path ); - return NULL; - } //end if - //initialize item config - ic = (itemconfig_t *) GetClearedHunkMemory(sizeof(itemconfig_t) + - max_iteminfo * sizeof(iteminfo_t)); - ic->iteminfo = (iteminfo_t *) ((char *) ic + sizeof(itemconfig_t)); - ic->numiteminfo = 0; - //parse the item config file - while(PC_ReadToken(source, &token)) - { - if (!strcmp(token.string, "iteminfo")) - { - if (ic->numiteminfo >= max_iteminfo) - { - SourceError(source, "more than %d item info defined\n", max_iteminfo); - FreeMemory(ic); - FreeSource(source); - return NULL; - } //end if - ii = &ic->iteminfo[ic->numiteminfo]; - Com_Memset(ii, 0, sizeof(iteminfo_t)); - if (!PC_ExpectTokenType(source, TT_STRING, 0, &token)) - { - FreeMemory(ic); - FreeMemory(source); - return NULL; - } //end if - StripDoubleQuotes(token.string); - strncpy(ii->classname, token.string, sizeof(ii->classname)-1); - if (!ReadStructure(source, &iteminfo_struct, (char *) ii)) - { - FreeMemory(ic); - FreeSource(source); - return NULL; - } //end if - ii->number = ic->numiteminfo; - ic->numiteminfo++; - } //end if - else - { - SourceError(source, "unknown definition %s\n", token.string); - FreeMemory(ic); - FreeSource(source); - return NULL; - } //end else - } //end while - FreeSource(source); - // - if (!ic->numiteminfo) botimport.Print(PRT_WARNING, "no item info loaded\n"); - botimport.Print(PRT_MESSAGE, "loaded %s\n", path); - return ic; -} //end of the function LoadItemConfig -//=========================================================================== -// index to find the weight function of an iteminfo -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int *ItemWeightIndex(weightconfig_t *iwc, itemconfig_t *ic) -{ - int *index, i; - - //initialize item weight index - index = (int *) GetClearedMemory(sizeof(int) * ic->numiteminfo); - - for (i = 0; i < ic->numiteminfo; i++) - { - index[i] = FindFuzzyWeight(iwc, ic->iteminfo[i].classname); - if (index[i] < 0) - { - Log_Write("item info %d \"%s\" has no fuzzy weight\r\n", i, ic->iteminfo[i].classname); - } //end if - } //end for - return index; -} //end of the function ItemWeightIndex -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void InitLevelItemHeap(void) -{ - int i, max_levelitems; - - if (levelitemheap) FreeMemory(levelitemheap); - - max_levelitems = (int) LibVarValue("max_levelitems", "256"); - levelitemheap = (levelitem_t *) GetClearedMemory(max_levelitems * sizeof(levelitem_t)); - - for (i = 0; i < max_levelitems-1; i++) - { - levelitemheap[i].next = &levelitemheap[i + 1]; - } //end for - levelitemheap[max_levelitems-1].next = NULL; - // - freelevelitems = levelitemheap; -} //end of the function InitLevelItemHeap -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -levelitem_t *AllocLevelItem(void) -{ - levelitem_t *li; - - li = freelevelitems; - if (!li) - { - botimport.Print(PRT_FATAL, "out of level items\n"); - return NULL; - } //end if - // - freelevelitems = freelevelitems->next; - Com_Memset(li, 0, sizeof(levelitem_t)); - return li; -} //end of the function AllocLevelItem -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void FreeLevelItem(levelitem_t *li) -{ - li->next = freelevelitems; - freelevelitems = li; -} //end of the function FreeLevelItem -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AddLevelItemToList(levelitem_t *li) -{ - if (levelitems) levelitems->prev = li; - li->prev = NULL; - li->next = levelitems; - levelitems = li; -} //end of the function AddLevelItemToList -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void RemoveLevelItemFromList(levelitem_t *li) -{ - if (li->prev) li->prev->next = li->next; - else levelitems = li->next; - if (li->next) li->next->prev = li->prev; -} //end of the function RemoveLevelItemFromList -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotFreeInfoEntities(void) -{ - maplocation_t *ml, *nextml; - campspot_t *cs, *nextcs; - - for (ml = maplocations; ml; ml = nextml) - { - nextml = ml->next; - FreeMemory(ml); - } //end for - maplocations = NULL; - for (cs = campspots; cs; cs = nextcs) - { - nextcs = cs->next; - FreeMemory(cs); - } //end for - campspots = NULL; -} //end of the function BotFreeInfoEntities -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotInitInfoEntities(void) -{ - char classname[MAX_EPAIRKEY]; - maplocation_t *ml; - campspot_t *cs; - int ent, numlocations, numcampspots; - - BotFreeInfoEntities(); - // - numlocations = 0; - numcampspots = 0; - for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent)) - { - if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue; - - //map locations - if (!strcmp(classname, "target_location")) - { - ml = (maplocation_t *) GetClearedMemory(sizeof(maplocation_t)); - AAS_VectorForBSPEpairKey(ent, "origin", ml->origin); - AAS_ValueForBSPEpairKey(ent, "message", ml->name, sizeof(ml->name)); - ml->areanum = AAS_PointAreaNum(ml->origin); - ml->next = maplocations; - maplocations = ml; - numlocations++; - } //end if - //camp spots - else if (!strcmp(classname, "info_camp")) - { - cs = (campspot_t *) GetClearedMemory(sizeof(campspot_t)); - AAS_VectorForBSPEpairKey(ent, "origin", cs->origin); - //cs->origin[2] += 16; - AAS_ValueForBSPEpairKey(ent, "message", cs->name, sizeof(cs->name)); - AAS_FloatForBSPEpairKey(ent, "range", &cs->range); - AAS_FloatForBSPEpairKey(ent, "weight", &cs->weight); - AAS_FloatForBSPEpairKey(ent, "wait", &cs->wait); - AAS_FloatForBSPEpairKey(ent, "random", &cs->random); - cs->areanum = AAS_PointAreaNum(cs->origin); - if (!cs->areanum) - { - botimport.Print(PRT_MESSAGE, "camp spot at %1.1f %1.1f %1.1f in solid\n", cs->origin[0], cs->origin[1], cs->origin[2]); - FreeMemory(cs); - continue; - } //end if - cs->next = campspots; - campspots = cs; - //AAS_DrawPermanentCross(cs->origin, 4, LINECOLOR_YELLOW); - numcampspots++; - } //end else if - } //end for - if (bot_developer) - { - botimport.Print(PRT_MESSAGE, "%d map locations\n", numlocations); - botimport.Print(PRT_MESSAGE, "%d camp spots\n", numcampspots); - } //end if -} //end of the function BotInitInfoEntities -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotInitLevelItems(void) -{ - int i, spawnflags, value; - char classname[MAX_EPAIRKEY]; - vec3_t origin, end; - int ent, goalareanum; - itemconfig_t *ic; - levelitem_t *li; - bsp_trace_t trace; - - //initialize the map locations and camp spots - BotInitInfoEntities(); - - //initialize the level item heap - InitLevelItemHeap(); - levelitems = NULL; - numlevelitems = 0; - // - ic = itemconfig; - if (!ic) return; - - //if there's no AAS file loaded - if (!AAS_Loaded()) return; - - //update the modelindexes of the item info - for (i = 0; i < ic->numiteminfo; i++) - { - //ic->iteminfo[i].modelindex = AAS_IndexFromModel(ic->iteminfo[i].model); - if (!ic->iteminfo[i].modelindex) - { - Log_Write("item %s has modelindex 0", ic->iteminfo[i].classname); - } //end if - } //end for - - for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent)) - { - if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue; - // - spawnflags = 0; - AAS_IntForBSPEpairKey(ent, "spawnflags", &spawnflags); - // - for (i = 0; i < ic->numiteminfo; i++) - { - if (!strcmp(classname, ic->iteminfo[i].classname)) break; - } //end for - if (i >= ic->numiteminfo) - { - Log_Write("entity %s unknown item\r\n", classname); - continue; - } //end if - //get the origin of the item - if (!AAS_VectorForBSPEpairKey(ent, "origin", origin)) - { - botimport.Print(PRT_ERROR, "item %s without origin\n", classname); - continue; - } //end else - // - goalareanum = 0; - //if it is a floating item - if (spawnflags & 1) - { - //if the item is not floating in water - if (!(AAS_PointContents(origin) & CONTENTS_WATER)) - { - VectorCopy(origin, end); - end[2] -= 32; - trace = AAS_Trace(origin, ic->iteminfo[i].mins, ic->iteminfo[i].maxs, end, -1, CONTENTS_SOLID|CONTENTS_PLAYERCLIP); - //if the item not near the ground - if (trace.fraction >= 1) - { - //if the item is not reachable from a jumppad - goalareanum = AAS_BestReachableFromJumpPadArea(origin, ic->iteminfo[i].mins, ic->iteminfo[i].maxs); - Log_Write("item %s reachable from jumppad area %d\r\n", ic->iteminfo[i].classname, goalareanum); - //botimport.Print(PRT_MESSAGE, "item %s reachable from jumppad area %d\r\n", ic->iteminfo[i].classname, goalareanum); - if (!goalareanum) continue; - } //end if - } //end if - } //end if - - li = AllocLevelItem(); - if (!li) return; - // - li->number = ++numlevelitems; - li->timeout = 0; - li->entitynum = 0; - // - li->flags = 0; - AAS_IntForBSPEpairKey(ent, "notfree", &value); - if (value) li->flags |= IFL_NOTFREE; - AAS_IntForBSPEpairKey(ent, "notteam", &value); - if (value) li->flags |= IFL_NOTTEAM; - AAS_IntForBSPEpairKey(ent, "notsingle", &value); - if (value) li->flags |= IFL_NOTSINGLE; - AAS_IntForBSPEpairKey(ent, "notbot", &value); - if (value) li->flags |= IFL_NOTBOT; - if (!strcmp(classname, "item_botroam")) - { - li->flags |= IFL_ROAM; - AAS_FloatForBSPEpairKey(ent, "weight", &li->weight); - } //end if - //if not a stationary item - if (!(spawnflags & 1)) - { - if (!AAS_DropToFloor(origin, ic->iteminfo[i].mins, ic->iteminfo[i].maxs)) - { - botimport.Print(PRT_MESSAGE, "%s in solid at (%1.1f %1.1f %1.1f)\n", - classname, origin[0], origin[1], origin[2]); - } //end if - } //end if - //item info of the level item - li->iteminfo = i; - //origin of the item - VectorCopy(origin, li->origin); - // - if (goalareanum) - { - li->goalareanum = goalareanum; - VectorCopy(origin, li->goalorigin); - } //end if - else - { - //get the item goal area and goal origin - li->goalareanum = AAS_BestReachableArea(origin, - ic->iteminfo[i].mins, ic->iteminfo[i].maxs, - li->goalorigin); - if (!li->goalareanum) - { - botimport.Print(PRT_MESSAGE, "%s not reachable for bots at (%1.1f %1.1f %1.1f)\n", - classname, origin[0], origin[1], origin[2]); - } //end if - } //end else - // - AddLevelItemToList(li); - } //end for - botimport.Print(PRT_MESSAGE, "found %d level items\n", numlevelitems); -} //end of the function BotInitLevelItems -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotGoalName(int number, char *name, int size) -{ - levelitem_t *li; - - if (!itemconfig) return; - // - for (li = levelitems; li; li = li->next) - { - if (li->number == number) - { - strncpy(name, itemconfig->iteminfo[li->iteminfo].name, size-1); - name[size-1] = '\0'; - return; - } //end for - } //end for - strcpy(name, ""); - return; -} //end of the function BotGoalName -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotResetAvoidGoals(int goalstate) -{ - bot_goalstate_t *gs; - - gs = BotGoalStateFromHandle(goalstate); - if (!gs) return; - Com_Memset(gs->avoidgoals, 0, MAX_AVOIDGOALS * sizeof(int)); - Com_Memset(gs->avoidgoaltimes, 0, MAX_AVOIDGOALS * sizeof(float)); -} //end of the function BotResetAvoidGoals -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotDumpAvoidGoals(int goalstate) -{ - int i; - bot_goalstate_t *gs; - char name[32]; - - gs = BotGoalStateFromHandle(goalstate); - if (!gs) return; - for (i = 0; i < MAX_AVOIDGOALS; i++) - { - if (gs->avoidgoaltimes[i] >= AAS_Time()) - { - BotGoalName(gs->avoidgoals[i], name, 32); - Log_Write("avoid goal %s, number %d for %f seconds", name, - gs->avoidgoals[i], gs->avoidgoaltimes[i] - AAS_Time()); - } //end if - } //end for -} //end of the function BotDumpAvoidGoals -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotAddToAvoidGoals(bot_goalstate_t *gs, int number, float avoidtime) -{ - int i; - - for (i = 0; i < MAX_AVOIDGOALS; i++) - { - //if the avoid goal is already stored - if (gs->avoidgoals[i] == number) - { - gs->avoidgoals[i] = number; - gs->avoidgoaltimes[i] = AAS_Time() + avoidtime; - return; - } //end if - } //end for - - for (i = 0; i < MAX_AVOIDGOALS; i++) - { - //if this avoid goal has expired - if (gs->avoidgoaltimes[i] < AAS_Time()) - { - gs->avoidgoals[i] = number; - gs->avoidgoaltimes[i] = AAS_Time() + avoidtime; - return; - } //end if - } //end for -} //end of the function BotAddToAvoidGoals -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotRemoveFromAvoidGoals(int goalstate, int number) -{ - int i; - bot_goalstate_t *gs; - - gs = BotGoalStateFromHandle(goalstate); - if (!gs) return; - //don't use the goals the bot wants to avoid - for (i = 0; i < MAX_AVOIDGOALS; i++) - { - if (gs->avoidgoals[i] == number && gs->avoidgoaltimes[i] >= AAS_Time()) - { - gs->avoidgoaltimes[i] = 0; - return; - } //end if - } //end for -} //end of the function BotRemoveFromAvoidGoals -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -float BotAvoidGoalTime(int goalstate, int number) -{ - int i; - bot_goalstate_t *gs; - - gs = BotGoalStateFromHandle(goalstate); - if (!gs) return 0; - //don't use the goals the bot wants to avoid - for (i = 0; i < MAX_AVOIDGOALS; i++) - { - if (gs->avoidgoals[i] == number && gs->avoidgoaltimes[i] >= AAS_Time()) - { - return gs->avoidgoaltimes[i] - AAS_Time(); - } //end if - } //end for - return 0; -} //end of the function BotAvoidGoalTime -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotSetAvoidGoalTime(int goalstate, int number, float avoidtime) -{ - bot_goalstate_t *gs; - levelitem_t *li; - - gs = BotGoalStateFromHandle(goalstate); - if (!gs) - return; - if (avoidtime < 0) - { - if (!itemconfig) - return; - // - for (li = levelitems; li; li = li->next) - { - if (li->number == number) - { - avoidtime = itemconfig->iteminfo[li->iteminfo].respawntime; - if (!avoidtime) - avoidtime = AVOID_DEFAULT_TIME; - if (avoidtime < AVOID_MINIMUM_TIME) - avoidtime = AVOID_MINIMUM_TIME; - BotAddToAvoidGoals(gs, number, avoidtime); - return; - } //end for - } //end for - return; - } //end if - else - { - BotAddToAvoidGoals(gs, number, avoidtime); - } //end else -} //end of the function BotSetAvoidGoalTime -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotGetLevelItemGoal(int index, char *name, bot_goal_t *goal) -{ - levelitem_t *li; - - if (!itemconfig) return -1; - li = levelitems; - if (index >= 0) - { - for (; li; li = li->next) - { - if (li->number == index) - { - li = li->next; - break; - } //end if - } //end for - } //end for - for (; li; li = li->next) - { - // - if (g_gametype == GT_SINGLE_PLAYER) { - if (li->flags & IFL_NOTSINGLE) continue; - } - else if (g_gametype >= GT_TEAM) { - if (li->flags & IFL_NOTTEAM) continue; - } - else { - if (li->flags & IFL_NOTFREE) continue; - } - if (li->flags & IFL_NOTBOT) continue; - // - if (!Q_stricmp(name, itemconfig->iteminfo[li->iteminfo].name)) - { - goal->areanum = li->goalareanum; - VectorCopy(li->goalorigin, goal->origin); - goal->entitynum = li->entitynum; - VectorCopy(itemconfig->iteminfo[li->iteminfo].mins, goal->mins); - VectorCopy(itemconfig->iteminfo[li->iteminfo].maxs, goal->maxs); - goal->number = li->number; - goal->flags = GFL_ITEM; - if (li->timeout) goal->flags |= GFL_DROPPED; - //botimport.Print(PRT_MESSAGE, "found li %s\n", itemconfig->iteminfo[li->iteminfo].name); - return li->number; - } //end if - } //end for - return -1; -} //end of the function BotGetLevelItemGoal -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotGetMapLocationGoal(char *name, bot_goal_t *goal) -{ - maplocation_t *ml; - vec3_t mins = {-8, -8, -8}, maxs = {8, 8, 8}; - - for (ml = maplocations; ml; ml = ml->next) - { - if (!Q_stricmp(ml->name, name)) - { - goal->areanum = ml->areanum; - VectorCopy(ml->origin, goal->origin); - goal->entitynum = 0; - VectorCopy(mins, goal->mins); - VectorCopy(maxs, goal->maxs); - return qtrue; - } //end if - } //end for - return qfalse; -} //end of the function BotGetMapLocationGoal -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotGetNextCampSpotGoal(int num, bot_goal_t *goal) -{ - int i; - campspot_t *cs; - vec3_t mins = {-8, -8, -8}, maxs = {8, 8, 8}; - - if (num < 0) num = 0; - i = num; - for (cs = campspots; cs; cs = cs->next) - { - if (--i < 0) - { - goal->areanum = cs->areanum; - VectorCopy(cs->origin, goal->origin); - goal->entitynum = 0; - VectorCopy(mins, goal->mins); - VectorCopy(maxs, goal->maxs); - return num+1; - } //end if - } //end for - return 0; -} //end of the function BotGetNextCampSpotGoal -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotFindEntityForLevelItem(levelitem_t *li) -{ - int ent, modelindex; - itemconfig_t *ic; - aas_entityinfo_t entinfo; - vec3_t dir; - - ic = itemconfig; - if (!itemconfig) return; - for (ent = AAS_NextEntity(0); ent; ent = AAS_NextEntity(ent)) - { - //get the model index of the entity - modelindex = AAS_EntityModelindex(ent); - // - if (!modelindex) continue; - //get info about the entity - AAS_EntityInfo(ent, &entinfo); - //if the entity is still moving - if (entinfo.origin[0] != entinfo.lastvisorigin[0] || - entinfo.origin[1] != entinfo.lastvisorigin[1] || - entinfo.origin[2] != entinfo.lastvisorigin[2]) continue; - // - if (ic->iteminfo[li->iteminfo].modelindex == modelindex) - { - //check if the entity is very close - VectorSubtract(li->origin, entinfo.origin, dir); - if (VectorLength(dir) < 30) - { - //found an entity for this level item - li->entitynum = ent; - } //end if - } //end if - } //end for -} //end of the function BotFindEntityForLevelItem -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== - -//NOTE: enum entityType_t in bg_public.h -#define ET_ITEM 2 - -void BotUpdateEntityItems(void) -{ - int ent, i, modelindex; - vec3_t dir; - levelitem_t *li, *nextli; - aas_entityinfo_t entinfo; - itemconfig_t *ic; - - //timeout current entity items if necessary - for (li = levelitems; li; li = nextli) - { - nextli = li->next; - //if it is a item that will time out - if (li->timeout) - { - //timeout the item - if (li->timeout < AAS_Time()) - { - RemoveLevelItemFromList(li); - FreeLevelItem(li); - } //end if - } //end if - } //end for - //find new entity items - ic = itemconfig; - if (!itemconfig) return; - // - for (ent = AAS_NextEntity(0); ent; ent = AAS_NextEntity(ent)) - { - if (AAS_EntityType(ent) != ET_ITEM) continue; - //get the model index of the entity - modelindex = AAS_EntityModelindex(ent); - // - if (!modelindex) continue; - //get info about the entity - AAS_EntityInfo(ent, &entinfo); - //FIXME: don't do this - //skip all floating items for now - //if (entinfo.groundent != ENTITYNUM_WORLD) continue; - //if the entity is still moving - if (entinfo.origin[0] != entinfo.lastvisorigin[0] || - entinfo.origin[1] != entinfo.lastvisorigin[1] || - entinfo.origin[2] != entinfo.lastvisorigin[2]) continue; - //check if the entity is already stored as a level item - for (li = levelitems; li; li = li->next) - { - //if the level item is linked to an entity - if (li->entitynum && li->entitynum == ent) - { - //the entity is re-used if the models are different - if (ic->iteminfo[li->iteminfo].modelindex != modelindex) - { - //remove this level item - RemoveLevelItemFromList(li); - FreeLevelItem(li); - li = NULL; - break; - } //end if - else - { - if (entinfo.origin[0] != li->origin[0] || - entinfo.origin[1] != li->origin[1] || - entinfo.origin[2] != li->origin[2]) - { - VectorCopy(entinfo.origin, li->origin); - //also update the goal area number - li->goalareanum = AAS_BestReachableArea(li->origin, - ic->iteminfo[li->iteminfo].mins, ic->iteminfo[li->iteminfo].maxs, - li->goalorigin); - } //end if - break; - } //end else - } //end if - } //end for - if (li) continue; - //try to link the entity to a level item - for (li = levelitems; li; li = li->next) - { - //if this level item is already linked - if (li->entitynum) continue; - // - if (g_gametype == GT_SINGLE_PLAYER) { - if (li->flags & IFL_NOTSINGLE) continue; - } - else if (g_gametype >= GT_TEAM) { - if (li->flags & IFL_NOTTEAM) continue; - } - else { - if (li->flags & IFL_NOTFREE) continue; - } - //if the model of the level item and the entity are the same - if (ic->iteminfo[li->iteminfo].modelindex == modelindex) - { - //check if the entity is very close - VectorSubtract(li->origin, entinfo.origin, dir); - if (VectorLength(dir) < 30) - { - //found an entity for this level item - li->entitynum = ent; - //if the origin is different - if (entinfo.origin[0] != li->origin[0] || - entinfo.origin[1] != li->origin[1] || - entinfo.origin[2] != li->origin[2]) - { - //update the level item origin - VectorCopy(entinfo.origin, li->origin); - //also update the goal area number - li->goalareanum = AAS_BestReachableArea(li->origin, - ic->iteminfo[li->iteminfo].mins, ic->iteminfo[li->iteminfo].maxs, - li->goalorigin); - } //end if -#ifdef DEBUG - Log_Write("linked item %s to an entity", ic->iteminfo[li->iteminfo].classname); -#endif //DEBUG - break; - } //end if - } //end else - } //end for - if (li) continue; - //check if the model is from a known item - for (i = 0; i < ic->numiteminfo; i++) - { - if (ic->iteminfo[i].modelindex == modelindex) - { - break; - } //end if - } //end for - //if the model is not from a known item - if (i >= ic->numiteminfo) continue; - //allocate a new level item - li = AllocLevelItem(); - // - if (!li) continue; - //entity number of the level item - li->entitynum = ent; - //number for the level item - li->number = numlevelitems + ent; - //set the item info index for the level item - li->iteminfo = i; - //origin of the item - VectorCopy(entinfo.origin, li->origin); - //get the item goal area and goal origin - li->goalareanum = AAS_BestReachableArea(li->origin, - ic->iteminfo[i].mins, ic->iteminfo[i].maxs, - li->goalorigin); - //never go for items dropped into jumppads - if (AAS_AreaJumpPad(li->goalareanum)) - { - FreeLevelItem(li); - continue; - } //end if - //time this item out after 30 seconds - //dropped items disappear after 30 seconds - li->timeout = AAS_Time() + 30; - //add the level item to the list - AddLevelItemToList(li); - //botimport.Print(PRT_MESSAGE, "found new level item %s\n", ic->iteminfo[i].classname); - } //end for - /* - for (li = levelitems; li; li = li->next) - { - if (!li->entitynum) - { - BotFindEntityForLevelItem(li); - } //end if - } //end for*/ -} //end of the function BotUpdateEntityItems -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotDumpGoalStack(int goalstate) -{ - int i; - bot_goalstate_t *gs; - char name[32]; - - gs = BotGoalStateFromHandle(goalstate); - if (!gs) return; - for (i = 1; i <= gs->goalstacktop; i++) - { - BotGoalName(gs->goalstack[i].number, name, 32); - Log_Write("%d: %s", i, name); - } //end for -} //end of the function BotDumpGoalStack -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotPushGoal(int goalstate, bot_goal_t *goal) -{ - bot_goalstate_t *gs; - - gs = BotGoalStateFromHandle(goalstate); - if (!gs) return; - if (gs->goalstacktop >= MAX_GOALSTACK-1) - { - botimport.Print(PRT_ERROR, "goal heap overflow\n"); - BotDumpGoalStack(goalstate); - return; - } //end if - gs->goalstacktop++; - Com_Memcpy(&gs->goalstack[gs->goalstacktop], goal, sizeof(bot_goal_t)); -} //end of the function BotPushGoal -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotPopGoal(int goalstate) -{ - bot_goalstate_t *gs; - - gs = BotGoalStateFromHandle(goalstate); - if (!gs) return; - if (gs->goalstacktop > 0) gs->goalstacktop--; -} //end of the function BotPopGoal -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotEmptyGoalStack(int goalstate) -{ - bot_goalstate_t *gs; - - gs = BotGoalStateFromHandle(goalstate); - if (!gs) return; - gs->goalstacktop = 0; -} //end of the function BotEmptyGoalStack -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotGetTopGoal(int goalstate, bot_goal_t *goal) -{ - bot_goalstate_t *gs; - - gs = BotGoalStateFromHandle(goalstate); - if (!gs) return qfalse; - if (!gs->goalstacktop) return qfalse; - Com_Memcpy(goal, &gs->goalstack[gs->goalstacktop], sizeof(bot_goal_t)); - return qtrue; -} //end of the function BotGetTopGoal -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotGetSecondGoal(int goalstate, bot_goal_t *goal) -{ - bot_goalstate_t *gs; - - gs = BotGoalStateFromHandle(goalstate); - if (!gs) return qfalse; - if (gs->goalstacktop <= 1) return qfalse; - Com_Memcpy(goal, &gs->goalstack[gs->goalstacktop-1], sizeof(bot_goal_t)); - return qtrue; -} //end of the function BotGetSecondGoal -//=========================================================================== -// pops a new long term goal on the goal stack in the goalstate -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotChooseLTGItem(int goalstate, vec3_t origin, int *inventory, int travelflags) -{ - int areanum, t, weightnum; - 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; - //the item configuration - ic = itemconfig; - if (!itemconfig) - return qfalse; - //best weight and item so far - bestweight = 0; - bestitem = NULL; - Com_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->flags & IFL_NOTSINGLE) - continue; - } - else if (g_gametype >= GT_TEAM) { - if (li->flags & IFL_NOTTEAM) - continue; - } - else { - if (li->flags & IFL_NOTFREE) - continue; - } - if (li->flags & IFL_NOTBOT) - continue; - //if the item is not 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 (!li->entitynum && !(li->flags & IFL_ROAM)) - continue; - //get the fuzzy weight function for this item - iteminfo = &ic->iteminfo[li->iteminfo]; - weightnum = gs->itemweightindex[iteminfo->number]; - if (weightnum < 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 += droppedweight->value; -#endif //DROPPEDWEIGHT - //use weight scale for item_botroam - if (li->flags & IFL_ROAM) weight *= li->weight; - // - 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) - { - //if this item won't respawn before we get there - avoidtime = BotAvoidGoalTime(goalstate, li->number); - if (avoidtime - t * 0.009 > 0) - continue; - // - weight /= (float) t * TRAVELTIME_SCALE; - // - if (weight > bestweight) - { - bestweight = weight; - bestitem = li; - } //end if - } //end if - } //end if - } //end for - //if no goal item found - if (!bestitem) - { - /* - //if not in lava or slime - if (!AAS_AreaLava(areanum) && !AAS_AreaSlime(areanum)) - { - if (AAS_RandomGoalArea(areanum, travelflags, &goal.areanum, goal.origin)) - { - VectorSet(goal.mins, -15, -15, -15); - VectorSet(goal.maxs, 15, 15, 15); - goal.entitynum = 0; - goal.number = 0; - goal.flags = GFL_ROAM; - goal.iteminfo = 0; - //push the goal on the stack - BotPushGoal(goalstate, &goal); - // -#ifdef DEBUG - botimport.Print(PRT_MESSAGE, "chosen roam goal area %d\n", goal.areanum); -#endif //DEBUG - return qtrue; - } //end if - } //end if - */ - return qfalse; - } //end if - //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; - if (bestitem->timeout) - goal.flags |= GFL_DROPPED; - if (bestitem->flags & IFL_ROAM) - goal.flags |= GFL_ROAM; - goal.iteminfo = bestitem->iteminfo; - //if it's a dropped item - if (bestitem->timeout) - { - avoidtime = AVOID_DROPPED_TIME; - } //end if - else - { - avoidtime = iteminfo->respawntime; - if (!avoidtime) - avoidtime = AVOID_DEFAULT_TIME; - if (avoidtime < AVOID_MINIMUM_TIME) - avoidtime = AVOID_MINIMUM_TIME; - } //end else - //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); - // - return qtrue; -} //end of the function BotChooseLTGItem -//=========================================================================== -// -// 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; - Com_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->flags & IFL_NOTSINGLE) - continue; - } - else if (g_gametype >= GT_TEAM) { - if (li->flags & IFL_NOTTEAM) - continue; - } - else { - if (li->flags & IFL_NOTFREE) - continue; - } - if (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 (!li->entitynum && !(li->flags & IFL_ROAM)) - continue; - //get the fuzzy weight function for this item - iteminfo = &ic->iteminfo[li->iteminfo]; - weightnum = gs->itemweightindex[iteminfo->number]; - if (weightnum < 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 += droppedweight->value; -#endif //DROPPEDWEIGHT - //use weight scale for item_botroam - if (li->flags & IFL_ROAM) weight *= li->weight; - // - 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) - { - //if this item won't respawn before we get there - 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); - } //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; - if (bestitem->timeout) - goal.flags |= GFL_DROPPED; - if (bestitem->flags & IFL_ROAM) - goal.flags |= GFL_ROAM; - goal.iteminfo = bestitem->iteminfo; - //if it's a dropped item - if (bestitem->timeout) - { - avoidtime = AVOID_DROPPED_TIME; - } //end if - else - { - avoidtime = iteminfo->respawntime; - if (!avoidtime) - avoidtime = AVOID_DEFAULT_TIME; - if (avoidtime < AVOID_MINIMUM_TIME) - avoidtime = AVOID_MINIMUM_TIME; - } //end else - //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); - // - return qtrue; -} //end of the function BotChooseNBGItem -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotTouchingGoal(vec3_t origin, bot_goal_t *goal) -{ - int i; - vec3_t boxmins, boxmaxs; - vec3_t absmins, absmaxs; - vec3_t safety_maxs = {0, 0, 0}; //{4, 4, 10}; - vec3_t safety_mins = {0, 0, 0}; //{-4, -4, 0}; - - AAS_PresenceTypeBoundingBox(PRESENCE_NORMAL, boxmins, boxmaxs); - VectorSubtract(goal->mins, boxmaxs, absmins); - VectorSubtract(goal->maxs, boxmins, absmaxs); - VectorAdd(absmins, goal->origin, absmins); - VectorAdd(absmaxs, goal->origin, absmaxs); - //make the box a little smaller for safety - VectorSubtract(absmaxs, safety_maxs, absmaxs); - VectorSubtract(absmins, safety_mins, absmins); - - for (i = 0; i < 3; i++) - { - if (origin[i] < absmins[i] || origin[i] > absmaxs[i]) return qfalse; - } //end for - return qtrue; -} //end of the function BotTouchingGoal -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotItemGoalInVisButNotVisible(int viewer, vec3_t eye, vec3_t viewangles, bot_goal_t *goal) -{ - aas_entityinfo_t entinfo; - bsp_trace_t trace; - vec3_t middle; - - if (!(goal->flags & GFL_ITEM)) return qfalse; - // - VectorAdd(goal->mins, goal->mins, middle); - VectorScale(middle, 0.5, middle); - VectorAdd(goal->origin, middle, middle); - // - trace = AAS_Trace(eye, NULL, NULL, middle, viewer, CONTENTS_SOLID); - //if the goal middle point is visible - if (trace.fraction >= 1) - { - //the goal entity number doesn't have to be valid - //just assume it's valid - if (goal->entitynum <= 0) - return qfalse; - // - //if the entity data isn't valid - AAS_EntityInfo(goal->entitynum, &entinfo); - //NOTE: for some wacko reason entities are sometimes - // not updated - //if (!entinfo.valid) return qtrue; - if (entinfo.ltime < AAS_Time() - 0.5) - return qtrue; - } //end if - return qfalse; -} //end of the function BotItemGoalInVisButNotVisible -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotResetGoalState(int goalstate) -{ - bot_goalstate_t *gs; - - gs = BotGoalStateFromHandle(goalstate); - if (!gs) return; - Com_Memset(gs->goalstack, 0, MAX_GOALSTACK * sizeof(bot_goal_t)); - gs->goalstacktop = 0; - BotResetAvoidGoals(goalstate); -} //end of the function BotResetGoalState -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotLoadItemWeights(int goalstate, char *filename) -{ - bot_goalstate_t *gs; - - gs = BotGoalStateFromHandle(goalstate); - if (!gs) return BLERR_CANNOTLOADITEMWEIGHTS; - //load the weight configuration - gs->itemweightconfig = ReadWeightConfig(filename); - if (!gs->itemweightconfig) - { - botimport.Print(PRT_FATAL, "couldn't load weights\n"); - return BLERR_CANNOTLOADITEMWEIGHTS; - } //end if - //if there's no item configuration - if (!itemconfig) return BLERR_CANNOTLOADITEMWEIGHTS; - //create the item weight index - gs->itemweightindex = ItemWeightIndex(gs->itemweightconfig, itemconfig); - //everything went ok - return BLERR_NOERROR; -} //end of the function BotLoadItemWeights -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotFreeItemWeights(int goalstate) -{ - bot_goalstate_t *gs; - - gs = BotGoalStateFromHandle(goalstate); - if (!gs) return; - if (gs->itemweightconfig) FreeWeightConfig(gs->itemweightconfig); - if (gs->itemweightindex) FreeMemory(gs->itemweightindex); -} //end of the function BotFreeItemWeights -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotAllocGoalState(int client) -{ - int i; - - for (i = 1; i <= MAX_CLIENTS; i++) - { - if (!botgoalstates[i]) - { - botgoalstates[i] = GetClearedMemory(sizeof(bot_goalstate_t)); - botgoalstates[i]->client = client; - return i; - } //end if - } //end for - return 0; -} //end of the function BotAllocGoalState -//======================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//======================================================================== -void BotFreeGoalState(int handle) -{ - if (handle <= 0 || handle > MAX_CLIENTS) - { - botimport.Print(PRT_FATAL, "goal state handle %d out of range\n", handle); - return; - } //end if - if (!botgoalstates[handle]) - { - botimport.Print(PRT_FATAL, "invalid goal state handle %d\n", handle); - return; - } //end if - BotFreeItemWeights(handle); - FreeMemory(botgoalstates[handle]); - botgoalstates[handle] = NULL; -} //end of the function BotFreeGoalState -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotSetupGoalAI(void) -{ - char *filename; - - //check if teamplay is on - g_gametype = LibVarValue("g_gametype", "0"); - //item configuration file - filename = LibVarString("itemconfig", "items.c"); - //load the item configuration - itemconfig = LoadItemConfig(filename); - if (!itemconfig) - { - botimport.Print(PRT_FATAL, "couldn't load item config\n"); - return BLERR_CANNOTLOADITEMCONFIG; - } //end if - // - droppedweight = LibVar("droppedweight", "1000"); - //everything went ok - return BLERR_NOERROR; -} //end of the function BotSetupGoalAI -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotShutdownGoalAI(void) -{ - int i; - - if (itemconfig) FreeMemory(itemconfig); - itemconfig = NULL; - if (levelitemheap) FreeMemory(levelitemheap); - levelitemheap = NULL; - freelevelitems = NULL; - levelitems = NULL; - numlevelitems = 0; - - BotFreeInfoEntities(); - - for (i = 1; i <= MAX_CLIENTS; i++) - { - if (botgoalstates[i]) - { - BotFreeGoalState(i); - } //end if - } //end for -} //end of the function BotShutdownGoalAI diff --git a/src/botlib/be_ai_goal.h b/src/botlib/be_ai_goal.h deleted file mode 100644 index e0d59aaa..00000000 --- a/src/botlib/be_ai_goal.h +++ /dev/null @@ -1,119 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// -/***************************************************************************** - * name: be_ai_goal.h - * - * desc: goal AI - * - * $Archive: /source/code/botlib/be_ai_goal.h $ - * - *****************************************************************************/ - -#define MAX_AVOIDGOALS 256 -#define MAX_GOALSTACK 8 - -#define GFL_NONE 0 -#define GFL_ITEM 1 -#define GFL_ROAM 2 -#define GFL_DROPPED 4 - -//a bot goal -typedef struct bot_goal_s -{ - vec3_t origin; //origin of the goal - int areanum; //area number of the goal - vec3_t mins, maxs; //mins and maxs of the goal - int entitynum; //number of the goal entity - int number; //goal number - int flags; //goal flags - int iteminfo; //item information -} bot_goal_t; - -//reset the whole goal state, but keep the item weights -void BotResetGoalState(int goalstate); -//reset avoid goals -void BotResetAvoidGoals(int goalstate); -//remove the goal with the given number from the avoid goals -void BotRemoveFromAvoidGoals(int goalstate, int number); -//push a goal onto the goal stack -void BotPushGoal(int goalstate, bot_goal_t *goal); -//pop a goal from the goal stack -void BotPopGoal(int goalstate); -//empty the bot's goal stack -void BotEmptyGoalStack(int goalstate); -//dump the avoid goals -void BotDumpAvoidGoals(int goalstate); -//dump the goal stack -void BotDumpGoalStack(int goalstate); -//get the name name of the goal with the given number -void BotGoalName(int number, char *name, int size); -//get the top goal from the stack -int BotGetTopGoal(int goalstate, bot_goal_t *goal); -//get the second goal on the stack -int BotGetSecondGoal(int goalstate, bot_goal_t *goal); -//choose the best long term goal item for the bot -int BotChooseLTGItem(int goalstate, vec3_t origin, int *inventory, int travelflags); -//choose the best nearby goal item for the bot -//the item may not be further away from the current bot position than maxtime -//also the travel time from the nearby goal towards the long term goal may not -//be larger than the travel time towards the long term goal from the current bot position -int BotChooseNBGItem(int goalstate, vec3_t origin, int *inventory, int travelflags, - bot_goal_t *ltg, float maxtime); -//returns true if the bot touches the goal -int BotTouchingGoal(vec3_t origin, bot_goal_t *goal); -//returns true if the goal should be visible but isn't -int BotItemGoalInVisButNotVisible(int viewer, vec3_t eye, vec3_t viewangles, bot_goal_t *goal); -//search for a goal for the given classname, the index can be used -//as a start point for the search when multiple goals are available with that same classname -int BotGetLevelItemGoal(int index, char *classname, bot_goal_t *goal); -//get the next camp spot in the map -int BotGetNextCampSpotGoal(int num, bot_goal_t *goal); -//get the map location with the given name -int BotGetMapLocationGoal(char *name, bot_goal_t *goal); -//returns the avoid goal time -float BotAvoidGoalTime(int goalstate, int number); -//set the avoid goal time -void BotSetAvoidGoalTime(int goalstate, int number, float avoidtime); -//initializes the items in the level -void BotInitLevelItems(void); -//regularly update dynamic entity items (dropped weapons, flags etc.) -void BotUpdateEntityItems(void); -//interbreed the goal fuzzy logic -void BotInterbreedGoalFuzzyLogic(int parent1, int parent2, int child); -//save the goal fuzzy logic to disk -void BotSaveGoalFuzzyLogic(int goalstate, char *filename); -//mutate the goal fuzzy logic -void BotMutateGoalFuzzyLogic(int goalstate, float range); -//loads item weights for the bot -int BotLoadItemWeights(int goalstate, char *filename); -//frees the item weights of the bot -void BotFreeItemWeights(int goalstate); -//returns the handle of a newly allocated goal state -int BotAllocGoalState(int client); -//free the given goal state -void BotFreeGoalState(int handle); -//setup the goal AI -int BotSetupGoalAI(void); -//shut down the goal AI -void BotShutdownGoalAI(void); diff --git a/src/botlib/be_ai_move.c b/src/botlib/be_ai_move.c deleted file mode 100644 index 363137a1..00000000 --- a/src/botlib/be_ai_move.c +++ /dev/null @@ -1,3573 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_ai_move.c - * - * desc: bot movement AI - * - * $Archive: /MissionPack/code/botlib/be_ai_move.c $ - * - *****************************************************************************/ - -#include "../qcommon/q_shared.h" -#include "l_memory.h" -#include "l_libvar.h" -#include "l_utils.h" -#include "l_script.h" -#include "l_precomp.h" -#include "l_struct.h" -#include "aasfile.h" -#include "botlib.h" -#include "be_aas.h" -#include "be_aas_funcs.h" -#include "be_interface.h" - -#include "be_ea.h" -#include "be_ai_goal.h" -#include "be_ai_move.h" - - -//#define DEBUG_AI_MOVE -//#define DEBUG_ELEVATOR -//#define DEBUG_GRAPPLE - -// bk001204 - redundant bot_avoidspot_t, see be_ai_move.h - -//movement state -//NOTE: the moveflags MFL_ONGROUND, MFL_TELEPORTED, MFL_WATERJUMP and -// MFL_GRAPPLEPULL must be set outside the movement code -typedef struct bot_movestate_s -{ - //input vars (all set outside the movement code) - vec3_t origin; //origin of the bot - vec3_t velocity; //velocity of the bot - vec3_t viewoffset; //view offset - int entitynum; //entity number of the bot - int client; //client number of the bot - float thinktime; //time the bot thinks - int presencetype; //presencetype of the bot - vec3_t viewangles; //view angles of the bot - //state vars - int areanum; //area the bot is in - int lastareanum; //last area the bot was in - int lastgoalareanum; //last goal area number - int lastreachnum; //last reachability number - vec3_t lastorigin; //origin previous cycle - int reachareanum; //area number of the reachabilty - int moveflags; //movement flags - int jumpreach; //set when jumped - float grapplevisible_time; //last time the grapple was visible - float lastgrappledist; //last distance to the grapple end - float reachability_time; //time to use current reachability - int avoidreach[MAX_AVOIDREACH]; //reachabilities to avoid - float avoidreachtimes[MAX_AVOIDREACH]; //times to avoid the reachabilities - int avoidreachtries[MAX_AVOIDREACH]; //number of tries before avoiding - // - bot_avoidspot_t avoidspots[MAX_AVOIDSPOTS]; //spots to avoid - int numavoidspots; -} bot_movestate_t; - -//used to avoid reachability links for some time after being used -#define AVOIDREACH -#define AVOIDREACH_TIME 6 //avoid links for 6 seconds after use -#define AVOIDREACH_TRIES 4 -//prediction times -#define PREDICTIONTIME_JUMP 3 //in seconds -#define PREDICTIONTIME_MOVE 2 //in seconds -//weapon indexes for weapon jumping -#define WEAPONINDEX_ROCKET_LAUNCHER 5 -#define WEAPONINDEX_BFG 9 - -#define MODELTYPE_FUNC_PLAT 1 -#define MODELTYPE_FUNC_BOB 2 -#define MODELTYPE_FUNC_DOOR 3 -#define MODELTYPE_FUNC_STATIC 4 - -libvar_t *sv_maxstep; -libvar_t *sv_maxbarrier; -libvar_t *sv_gravity; -libvar_t *weapindex_rocketlauncher; -libvar_t *weapindex_bfg10k; -libvar_t *weapindex_grapple; -libvar_t *entitytypemissile; -libvar_t *offhandgrapple; -libvar_t *cmd_grappleoff; -libvar_t *cmd_grappleon; -//type of model, func_plat or func_bobbing -int modeltypes[MAX_MODELS]; - -bot_movestate_t *botmovestates[MAX_CLIENTS+1]; - -//======================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//======================================================================== -int BotAllocMoveState(void) -{ - int i; - - for (i = 1; i <= MAX_CLIENTS; i++) - { - if (!botmovestates[i]) - { - botmovestates[i] = GetClearedMemory(sizeof(bot_movestate_t)); - return i; - } //end if - } //end for - return 0; -} //end of the function BotAllocMoveState -//======================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//======================================================================== -void BotFreeMoveState(int handle) -{ - if (handle <= 0 || handle > MAX_CLIENTS) - { - botimport.Print(PRT_FATAL, "move state handle %d out of range\n", handle); - return; - } //end if - if (!botmovestates[handle]) - { - botimport.Print(PRT_FATAL, "invalid move state %d\n", handle); - return; - } //end if - FreeMemory(botmovestates[handle]); - botmovestates[handle] = NULL; -} //end of the function BotFreeMoveState -//======================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//======================================================================== -bot_movestate_t *BotMoveStateFromHandle(int handle) -{ - if (handle <= 0 || handle > MAX_CLIENTS) - { - botimport.Print(PRT_FATAL, "move state handle %d out of range\n", handle); - return NULL; - } //end if - if (!botmovestates[handle]) - { - botimport.Print(PRT_FATAL, "invalid move state %d\n", handle); - return NULL; - } //end if - return botmovestates[handle]; -} //end of the function BotMoveStateFromHandle -//======================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//======================================================================== -void BotInitMoveState(int handle, bot_initmove_t *initmove) -{ - bot_movestate_t *ms; - - ms = BotMoveStateFromHandle(handle); - if (!ms) return; - VectorCopy(initmove->origin, ms->origin); - VectorCopy(initmove->velocity, ms->velocity); - VectorCopy(initmove->viewoffset, ms->viewoffset); - ms->entitynum = initmove->entitynum; - ms->client = initmove->client; - ms->thinktime = initmove->thinktime; - ms->presencetype = initmove->presencetype; - VectorCopy(initmove->viewangles, ms->viewangles); - // - ms->moveflags &= ~MFL_ONGROUND; - if (initmove->or_moveflags & MFL_ONGROUND) ms->moveflags |= MFL_ONGROUND; - ms->moveflags &= ~MFL_TELEPORTED; - if (initmove->or_moveflags & MFL_TELEPORTED) ms->moveflags |= MFL_TELEPORTED; - ms->moveflags &= ~MFL_WATERJUMP; - if (initmove->or_moveflags & MFL_WATERJUMP) ms->moveflags |= MFL_WATERJUMP; - ms->moveflags &= ~MFL_WALK; - if (initmove->or_moveflags & MFL_WALK) ms->moveflags |= MFL_WALK; - ms->moveflags &= ~MFL_GRAPPLEPULL; - if (initmove->or_moveflags & MFL_GRAPPLEPULL) ms->moveflags |= MFL_GRAPPLEPULL; -} //end of the function BotInitMoveState -//======================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//======================================================================== -float AngleDiff(float ang1, float ang2) -{ - float diff; - - diff = ang1 - ang2; - if (ang1 > ang2) - { - if (diff > 180.0) diff -= 360.0; - } //end if - else - { - if (diff < -180.0) diff += 360.0; - } //end else - return diff; -} //end of the function AngleDiff -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotFuzzyPointReachabilityArea(vec3_t origin) -{ - int firstareanum, j, x, y, z; - int areas[10], numareas, areanum, bestareanum; - float dist, bestdist; - vec3_t points[10], v, end; - - firstareanum = 0; - areanum = AAS_PointAreaNum(origin); - if (areanum) - { - firstareanum = areanum; - if (AAS_AreaReachability(areanum)) return areanum; - } //end if - VectorCopy(origin, end); - end[2] += 4; - numareas = AAS_TraceAreas(origin, end, areas, points, 10); - for (j = 0; j < numareas; j++) - { - if (AAS_AreaReachability(areas[j])) return areas[j]; - } //end for - bestdist = 999999; - bestareanum = 0; - for (z = 1; z >= -1; z -= 1) - { - for (x = 1; x >= -1; x -= 1) - { - for (y = 1; y >= -1; y -= 1) - { - VectorCopy(origin, end); - end[0] += x * 8; - end[1] += y * 8; - end[2] += z * 12; - numareas = AAS_TraceAreas(origin, end, areas, points, 10); - for (j = 0; j < numareas; j++) - { - if (AAS_AreaReachability(areas[j])) - { - VectorSubtract(points[j], origin, v); - dist = VectorLength(v); - if (dist < bestdist) - { - bestareanum = areas[j]; - bestdist = dist; - } //end if - } //end if - if (!firstareanum) firstareanum = areas[j]; - } //end for - } //end for - } //end for - if (bestareanum) return bestareanum; - } //end for - return firstareanum; -} //end of the function BotFuzzyPointReachabilityArea -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotReachabilityArea(vec3_t origin, int client) -{ - int modelnum, modeltype, reachnum, areanum; - aas_reachability_t reach; - vec3_t org, end, mins, maxs, up = {0, 0, 1}; - bsp_trace_t bsptrace; - aas_trace_t trace; - - //check if the bot is standing on something - AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, mins, maxs); - VectorMA(origin, -3, up, end); - bsptrace = AAS_Trace(origin, mins, maxs, end, client, CONTENTS_SOLID|CONTENTS_PLAYERCLIP); - if (!bsptrace.startsolid && bsptrace.fraction < 1 && bsptrace.ent != ENTITYNUM_NONE) - { - //if standing on the world the bot should be in a valid area - if (bsptrace.ent == ENTITYNUM_WORLD) - { - return BotFuzzyPointReachabilityArea(origin); - } //end if - - modelnum = AAS_EntityModelindex(bsptrace.ent); - modeltype = modeltypes[modelnum]; - - //if standing on a func_plat or func_bobbing then the bot is assumed to be - //in the area the reachability points to - if (modeltype == MODELTYPE_FUNC_PLAT || modeltype == MODELTYPE_FUNC_BOB) - { - reachnum = AAS_NextModelReachability(0, modelnum); - if (reachnum) - { - AAS_ReachabilityFromNum(reachnum, &reach); - return reach.areanum; - } //end if - } //end else if - - //if the bot is swimming the bot should be in a valid area - if (AAS_Swimming(origin)) - { - return BotFuzzyPointReachabilityArea(origin); - } //end if - // - areanum = BotFuzzyPointReachabilityArea(origin); - //if the bot is in an area with reachabilities - if (areanum && AAS_AreaReachability(areanum)) return areanum; - //trace down till the ground is hit because the bot is standing on some other entity - VectorCopy(origin, org); - VectorCopy(org, end); - end[2] -= 800; - trace = AAS_TraceClientBBox(org, end, PRESENCE_CROUCH, -1); - if (!trace.startsolid) - { - VectorCopy(trace.endpos, org); - } //end if - // - return BotFuzzyPointReachabilityArea(org); - } //end if - // - return BotFuzzyPointReachabilityArea(origin); -} //end of the function BotReachabilityArea -//=========================================================================== -// returns the reachability area the bot is in -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -/* -int BotReachabilityArea(vec3_t origin, int testground) -{ - int firstareanum, i, j, x, y, z; - int areas[10], numareas, areanum, bestareanum; - float dist, bestdist; - vec3_t org, end, points[10], v; - aas_trace_t trace; - - firstareanum = 0; - for (i = 0; i < 2; i++) - { - VectorCopy(origin, org); - //if test at the ground (used when bot is standing on an entity) - if (i > 0) - { - VectorCopy(origin, end); - end[2] -= 800; - trace = AAS_TraceClientBBox(origin, end, PRESENCE_CROUCH, -1); - if (!trace.startsolid) - { - VectorCopy(trace.endpos, org); - } //end if - } //end if - - firstareanum = 0; - areanum = AAS_PointAreaNum(org); - if (areanum) - { - firstareanum = areanum; - if (AAS_AreaReachability(areanum)) return areanum; - } //end if - bestdist = 999999; - bestareanum = 0; - for (z = 1; z >= -1; z -= 1) - { - for (x = 1; x >= -1; x -= 1) - { - for (y = 1; y >= -1; y -= 1) - { - VectorCopy(org, end); - end[0] += x * 8; - end[1] += y * 8; - end[2] += z * 12; - numareas = AAS_TraceAreas(org, end, areas, points, 10); - for (j = 0; j < numareas; j++) - { - if (AAS_AreaReachability(areas[j])) - { - VectorSubtract(points[j], org, v); - dist = VectorLength(v); - if (dist < bestdist) - { - bestareanum = areas[j]; - bestdist = dist; - } //end if - } //end if - } //end for - } //end for - } //end for - if (bestareanum) return bestareanum; - } //end for - if (!testground) break; - } //end for -//#ifdef DEBUG - //botimport.Print(PRT_MESSAGE, "no reachability area\n"); -//#endif //DEBUG - return firstareanum; -} //end of the function BotReachabilityArea*/ -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotOnMover(vec3_t origin, int entnum, aas_reachability_t *reach) -{ - int i, modelnum; - vec3_t mins, maxs, modelorigin, org, end; - vec3_t angles = {0, 0, 0}; - vec3_t boxmins = {-16, -16, -8}, boxmaxs = {16, 16, 8}; - bsp_trace_t trace; - - modelnum = reach->facenum & 0x0000FFFF; - //get some bsp model info - AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, NULL); - // - if (!AAS_OriginOfMoverWithModelNum(modelnum, modelorigin)) - { - botimport.Print(PRT_MESSAGE, "no entity with model %d\n", modelnum); - return qfalse; - } //end if - // - for (i = 0; i < 2; i++) - { - if (origin[i] > modelorigin[i] + maxs[i] + 16) return qfalse; - if (origin[i] < modelorigin[i] + mins[i] - 16) return qfalse; - } //end for - // - VectorCopy(origin, org); - org[2] += 24; - VectorCopy(origin, end); - end[2] -= 48; - // - trace = AAS_Trace(org, boxmins, boxmaxs, end, entnum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP); - if (!trace.startsolid && !trace.allsolid) - { - //NOTE: the reachability face number is the model number of the elevator - if (trace.ent != ENTITYNUM_NONE && AAS_EntityModelNum(trace.ent) == modelnum) - { - return qtrue; - } //end if - } //end if - return qfalse; -} //end of the function BotOnMover -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int MoverDown(aas_reachability_t *reach) -{ - int modelnum; - vec3_t mins, maxs, origin; - vec3_t angles = {0, 0, 0}; - - modelnum = reach->facenum & 0x0000FFFF; - //get some bsp model info - AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, origin); - // - if (!AAS_OriginOfMoverWithModelNum(modelnum, origin)) - { - botimport.Print(PRT_MESSAGE, "no entity with model %d\n", modelnum); - return qfalse; - } //end if - //if the top of the plat is below the reachability start point - if (origin[2] + maxs[2] < reach->start[2]) return qtrue; - return qfalse; -} //end of the function MoverDown -//======================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//======================================================================== -void BotSetBrushModelTypes(void) -{ - int ent, modelnum; - char classname[MAX_EPAIRKEY], model[MAX_EPAIRKEY]; - - Com_Memset(modeltypes, 0, MAX_MODELS * sizeof(int)); - // - for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent)) - { - if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue; - if (!AAS_ValueForBSPEpairKey(ent, "model", model, MAX_EPAIRKEY)) continue; - if (model[0]) modelnum = atoi(model+1); - else modelnum = 0; - - if (modelnum < 0 || modelnum > MAX_MODELS) - { - botimport.Print(PRT_MESSAGE, "entity %s model number out of range\n", classname); - continue; - } //end if - - if (!Q_stricmp(classname, "func_bobbing")) - modeltypes[modelnum] = MODELTYPE_FUNC_BOB; - else if (!Q_stricmp(classname, "func_plat")) - modeltypes[modelnum] = MODELTYPE_FUNC_PLAT; - else if (!Q_stricmp(classname, "func_door")) - modeltypes[modelnum] = MODELTYPE_FUNC_DOOR; - else if (!Q_stricmp(classname, "func_static")) - modeltypes[modelnum] = MODELTYPE_FUNC_STATIC; - } //end for -} //end of the function BotSetBrushModelTypes -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotOnTopOfEntity(bot_movestate_t *ms) -{ - vec3_t mins, maxs, end, up = {0, 0, 1}; - bsp_trace_t trace; - - AAS_PresenceTypeBoundingBox(ms->presencetype, mins, maxs); - VectorMA(ms->origin, -3, up, end); - trace = AAS_Trace(ms->origin, mins, maxs, end, ms->entitynum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP); - if (!trace.startsolid && (trace.ent != ENTITYNUM_WORLD && trace.ent != ENTITYNUM_NONE) ) - { - return trace.ent; - } //end if - return -1; -} //end of the function BotOnTopOfEntity -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotValidTravel(vec3_t origin, aas_reachability_t *reach, int travelflags) -{ - //if the reachability uses an unwanted travel type - if (AAS_TravelFlagForType(reach->traveltype) & ~travelflags) return qfalse; - //don't go into areas with bad travel types - if (AAS_AreaContentsTravelFlags(reach->areanum) & ~travelflags) return qfalse; - return qtrue; -} //end of the function BotValidTravel -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotAddToAvoidReach(bot_movestate_t *ms, int number, float avoidtime) -{ - int i; - - for (i = 0; i < MAX_AVOIDREACH; i++) - { - if (ms->avoidreach[i] == number) - { - if (ms->avoidreachtimes[i] > AAS_Time()) ms->avoidreachtries[i]++; - else ms->avoidreachtries[i] = 1; - ms->avoidreachtimes[i] = AAS_Time() + avoidtime; - return; - } //end if - } //end for - //add the reachability to the reachabilities to avoid for a while - for (i = 0; i < MAX_AVOIDREACH; i++) - { - if (ms->avoidreachtimes[i] < AAS_Time()) - { - ms->avoidreach[i] = number; - ms->avoidreachtimes[i] = AAS_Time() + avoidtime; - ms->avoidreachtries[i] = 1; - return; - } //end if - } //end for -} //end of the function BotAddToAvoidReach -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -float DistanceFromLineSquared(vec3_t p, vec3_t lp1, vec3_t lp2) -{ - vec3_t proj, dir; - int j; - - AAS_ProjectPointOntoVector(p, lp1, lp2, proj); - for (j = 0; j < 3; j++) - if ((proj[j] > lp1[j] && proj[j] > lp2[j]) || - (proj[j] < lp1[j] && proj[j] < lp2[j])) - break; - if (j < 3) { - if (fabs(proj[j] - lp1[j]) < fabs(proj[j] - lp2[j])) - VectorSubtract(p, lp1, dir); - else - VectorSubtract(p, lp2, dir); - return VectorLengthSquared(dir); - } - VectorSubtract(p, proj, dir); - return VectorLengthSquared(dir); -} //end of the function DistanceFromLineSquared -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -float VectorDistanceSquared(vec3_t p1, vec3_t p2) -{ - vec3_t dir; - VectorSubtract(p2, p1, dir); - return VectorLengthSquared(dir); -} //end of the function VectorDistanceSquared -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotAvoidSpots(vec3_t origin, aas_reachability_t *reach, bot_avoidspot_t *avoidspots, int numavoidspots) -{ - int checkbetween, i, type; - float squareddist, squaredradius; - - switch(reach->traveltype & TRAVELTYPE_MASK) - { - case TRAVEL_WALK: checkbetween = qtrue; break; - case TRAVEL_CROUCH: checkbetween = qtrue; break; - case TRAVEL_BARRIERJUMP: checkbetween = qtrue; break; - case TRAVEL_LADDER: checkbetween = qtrue; break; - case TRAVEL_WALKOFFLEDGE: checkbetween = qfalse; break; - case TRAVEL_JUMP: checkbetween = qfalse; break; - case TRAVEL_SWIM: checkbetween = qtrue; break; - case TRAVEL_WATERJUMP: checkbetween = qtrue; break; - case TRAVEL_TELEPORT: checkbetween = qfalse; break; - case TRAVEL_ELEVATOR: checkbetween = qfalse; break; - case TRAVEL_GRAPPLEHOOK: checkbetween = qfalse; break; - case TRAVEL_ROCKETJUMP: checkbetween = qfalse; break; - case TRAVEL_BFGJUMP: checkbetween = qfalse; break; - case TRAVEL_JUMPPAD: checkbetween = qfalse; break; - case TRAVEL_FUNCBOB: checkbetween = qfalse; break; - default: checkbetween = qtrue; break; - } //end switch - - type = AVOID_CLEAR; - for (i = 0; i < numavoidspots; i++) - { - squaredradius = Square(avoidspots[i].radius); - squareddist = DistanceFromLineSquared(avoidspots[i].origin, origin, reach->start); - // if moving towards the avoid spot - if (squareddist < squaredradius && - VectorDistanceSquared(avoidspots[i].origin, origin) > squareddist) - { - type = avoidspots[i].type; - } //end if - else if (checkbetween) { - squareddist = DistanceFromLineSquared(avoidspots[i].origin, reach->start, reach->end); - // if moving towards the avoid spot - if (squareddist < squaredradius && - VectorDistanceSquared(avoidspots[i].origin, reach->start) > squareddist) - { - type = avoidspots[i].type; - } //end if - } //end if - else - { - VectorDistanceSquared(avoidspots[i].origin, reach->end); - // if the reachability leads closer to the avoid spot - if (squareddist < squaredradius && - VectorDistanceSquared(avoidspots[i].origin, reach->start) > squareddist) - { - type = avoidspots[i].type; - } //end if - } //end else - if (type == AVOID_ALWAYS) - return type; - } //end for - return type; -} //end of the function BotAvoidSpots -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotAddAvoidSpot(int movestate, vec3_t origin, float radius, int type) -{ - bot_movestate_t *ms; - - ms = BotMoveStateFromHandle(movestate); - if (!ms) return; - if (type == AVOID_CLEAR) - { - ms->numavoidspots = 0; - return; - } //end if - - if (ms->numavoidspots >= MAX_AVOIDSPOTS) - return; - VectorCopy(origin, ms->avoidspots[ms->numavoidspots].origin); - ms->avoidspots[ms->numavoidspots].radius = radius; - ms->avoidspots[ms->numavoidspots].type = type; - ms->numavoidspots++; -} //end of the function BotAddAvoidSpot -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotGetReachabilityToGoal(vec3_t origin, int areanum, - int lastgoalareanum, int lastareanum, - int *avoidreach, float *avoidreachtimes, int *avoidreachtries, - bot_goal_t *goal, int travelflags, int movetravelflags, - struct bot_avoidspot_s *avoidspots, int numavoidspots, int *flags) -{ - int i, t, besttime, bestreachnum, reachnum; - aas_reachability_t reach; - - //if not in a valid area - if (!areanum) return 0; - // - if (AAS_AreaDoNotEnter(areanum) || AAS_AreaDoNotEnter(goal->areanum)) - { - travelflags |= TFL_DONOTENTER; - movetravelflags |= TFL_DONOTENTER; - } //end if - //use the routing to find the next area to go to - besttime = 0; - bestreachnum = 0; - // - for (reachnum = AAS_NextAreaReachability(areanum, 0); reachnum; - reachnum = AAS_NextAreaReachability(areanum, reachnum)) - { -#ifdef AVOIDREACH - //check if it isn't an reachability to avoid - for (i = 0; i < MAX_AVOIDREACH; i++) - { - if (avoidreach[i] == reachnum && avoidreachtimes[i] >= AAS_Time()) break; - } //end for - if (i != MAX_AVOIDREACH && avoidreachtries[i] > AVOIDREACH_TRIES) - { -#ifdef DEBUG - if (bot_developer) - { - botimport.Print(PRT_MESSAGE, "avoiding reachability %d\n", avoidreach[i]); - } //end if -#endif //DEBUG - continue; - } //end if -#endif //AVOIDREACH - //get the reachability from the number - AAS_ReachabilityFromNum(reachnum, &reach); - //NOTE: do not go back to the previous area if the goal didn't change - //NOTE: is this actually avoidance of local routing minima between two areas??? - if (lastgoalareanum == goal->areanum && reach.areanum == lastareanum) continue; - //if (AAS_AreaContentsTravelFlags(reach.areanum) & ~travelflags) continue; - //if the travel isn't valid - if (!BotValidTravel(origin, &reach, movetravelflags)) continue; - //get the travel time - t = AAS_AreaTravelTimeToGoalArea(reach.areanum, reach.end, goal->areanum, travelflags); - //if the goal area isn't reachable from the reachable area - if (!t) continue; - //if the bot should not use this reachability to avoid bad spots - if (BotAvoidSpots(origin, &reach, avoidspots, numavoidspots)) { - if (flags) { - *flags |= MOVERESULT_BLOCKEDBYAVOIDSPOT; - } - continue; - } - //add the travel time towards the area - t += reach.traveltime;// + AAS_AreaTravelTime(areanum, origin, reach.start); - //if the travel time is better than the ones already found - if (!besttime || t < besttime) - { - besttime = t; - bestreachnum = reachnum; - } //end if - } //end for - // - return bestreachnum; -} //end of the function BotGetReachabilityToGoal -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotAddToTarget(vec3_t start, vec3_t end, float maxdist, float *dist, vec3_t target) -{ - vec3_t dir; - float curdist; - - VectorSubtract(end, start, dir); - curdist = VectorNormalize(dir); - if (*dist + curdist < maxdist) - { - VectorCopy(end, target); - *dist += curdist; - return qfalse; - } //end if - else - { - VectorMA(start, maxdist - *dist, dir, target); - *dist = maxdist; - return qtrue; - } //end else -} //end of the function BotAddToTarget - -int BotMovementViewTarget(int movestate, bot_goal_t *goal, int travelflags, float lookahead, vec3_t target) -{ - aas_reachability_t reach; - int reachnum, lastareanum; - bot_movestate_t *ms; - vec3_t end; - float dist; - - ms = BotMoveStateFromHandle(movestate); - if (!ms) return qfalse; - reachnum = 0; - //if the bot has no goal or no last reachability - if (!ms->lastreachnum || !goal) return qfalse; - - reachnum = ms->lastreachnum; - VectorCopy(ms->origin, end); - lastareanum = ms->lastareanum; - dist = 0; - while(reachnum && dist < lookahead) - { - AAS_ReachabilityFromNum(reachnum, &reach); - if (BotAddToTarget(end, reach.start, lookahead, &dist, target)) return qtrue; - //never look beyond teleporters - if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_TELEPORT) return qtrue; - //never look beyond the weapon jump point - if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_ROCKETJUMP) return qtrue; - if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_BFGJUMP) return qtrue; - //don't add jump pad distances - if ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_JUMPPAD && - (reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_ELEVATOR && - (reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_FUNCBOB) - { - if (BotAddToTarget(reach.start, reach.end, lookahead, &dist, target)) return qtrue; - } //end if - reachnum = BotGetReachabilityToGoal(reach.end, reach.areanum, - ms->lastgoalareanum, lastareanum, - ms->avoidreach, ms->avoidreachtimes, ms->avoidreachtries, - goal, travelflags, travelflags, NULL, 0, NULL); - VectorCopy(reach.end, end); - lastareanum = reach.areanum; - if (lastareanum == goal->areanum) - { - BotAddToTarget(reach.end, goal->origin, lookahead, &dist, target); - return qtrue; - } //end if - } //end while - // - return qfalse; -} //end of the function BotMovementViewTarget -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotVisible(int ent, vec3_t eye, vec3_t target) -{ - bsp_trace_t trace; - - trace = AAS_Trace(eye, NULL, NULL, target, ent, CONTENTS_SOLID|CONTENTS_PLAYERCLIP); - if (trace.fraction >= 1) return qtrue; - return qfalse; -} //end of the function BotVisible -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotPredictVisiblePosition(vec3_t origin, int areanum, bot_goal_t *goal, int travelflags, vec3_t target) -{ - aas_reachability_t reach; - int reachnum, lastgoalareanum, lastareanum, i; - int avoidreach[MAX_AVOIDREACH]; - float avoidreachtimes[MAX_AVOIDREACH]; - int avoidreachtries[MAX_AVOIDREACH]; - vec3_t end; - - //if the bot has no goal or no last reachability - if (!goal) return qfalse; - //if the areanum is not valid - if (!areanum) return qfalse; - //if the goal areanum is not valid - if (!goal->areanum) return qfalse; - - Com_Memset(avoidreach, 0, MAX_AVOIDREACH * sizeof(int)); - lastgoalareanum = goal->areanum; - lastareanum = areanum; - VectorCopy(origin, end); - //only do 20 hops - for (i = 0; i < 20 && (areanum != goal->areanum); i++) - { - // - reachnum = BotGetReachabilityToGoal(end, areanum, - lastgoalareanum, lastareanum, - avoidreach, avoidreachtimes, avoidreachtries, - goal, travelflags, travelflags, NULL, 0, NULL); - if (!reachnum) return qfalse; - AAS_ReachabilityFromNum(reachnum, &reach); - // - if (BotVisible(goal->entitynum, goal->origin, reach.start)) - { - VectorCopy(reach.start, target); - return qtrue; - } //end if - // - if (BotVisible(goal->entitynum, goal->origin, reach.end)) - { - VectorCopy(reach.end, target); - return qtrue; - } //end if - // - if (reach.areanum == goal->areanum) - { - VectorCopy(reach.end, target); - return qtrue; - } //end if - // - lastareanum = areanum; - areanum = reach.areanum; - VectorCopy(reach.end, end); - // - } //end while - // - return qfalse; -} //end of the function BotPredictVisiblePosition -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void MoverBottomCenter(aas_reachability_t *reach, vec3_t bottomcenter) -{ - int modelnum; - vec3_t mins, maxs, origin, mids; - vec3_t angles = {0, 0, 0}; - - modelnum = reach->facenum & 0x0000FFFF; - //get some bsp model info - AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, origin); - // - if (!AAS_OriginOfMoverWithModelNum(modelnum, origin)) - { - botimport.Print(PRT_MESSAGE, "no entity with model %d\n", modelnum); - } //end if - //get a point just above the plat in the bottom position - VectorAdd(mins, maxs, mids); - VectorMA(origin, 0.5, mids, bottomcenter); - bottomcenter[2] = reach->start[2]; -} //end of the function MoverBottomCenter -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -float BotGapDistance(vec3_t origin, vec3_t hordir, int entnum) -{ - float dist, startz; - vec3_t start, end; - aas_trace_t trace; - - //do gap checking - startz = origin[2]; - //this enables walking down stairs more fluidly - { - VectorCopy(origin, start); - VectorCopy(origin, end); - end[2] -= 60; - trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, entnum); - if (trace.fraction >= 1) return 1; - startz = trace.endpos[2] + 1; - } - // - for (dist = 8; dist <= 100; dist += 8) - { - VectorMA(origin, dist, hordir, start); - start[2] = startz + 24; - VectorCopy(start, end); - end[2] -= 48 + sv_maxbarrier->value; - trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, entnum); - //if solid is found the bot can't walk any further and fall into a gap - if (!trace.startsolid) - { - //if it is a gap - if (trace.endpos[2] < startz - sv_maxstep->value - 8) - { - VectorCopy(trace.endpos, end); - end[2] -= 20; - if (AAS_PointContents(end) & CONTENTS_WATER) break; - //if a gap is found slow down - //botimport.Print(PRT_MESSAGE, "gap at %f\n", dist); - return dist; - } //end if - startz = trace.endpos[2]; - } //end if - } //end for - return 0; -} //end of the function BotGapDistance -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotCheckBarrierJump(bot_movestate_t *ms, vec3_t dir, float speed) -{ - vec3_t start, hordir, end; - aas_trace_t trace; - - VectorCopy(ms->origin, end); - end[2] += sv_maxbarrier->value; - //trace right up - trace = AAS_TraceClientBBox(ms->origin, end, PRESENCE_NORMAL, ms->entitynum); - //this shouldn't happen... but we check anyway - if (trace.startsolid) return qfalse; - //if very low ceiling it isn't possible to jump up to a barrier - if (trace.endpos[2] - ms->origin[2] < sv_maxstep->value) return qfalse; - // - hordir[0] = dir[0]; - hordir[1] = dir[1]; - hordir[2] = 0; - VectorNormalize(hordir); - VectorMA(ms->origin, ms->thinktime * speed * 0.5, hordir, end); - VectorCopy(trace.endpos, start); - end[2] = trace.endpos[2]; - //trace from previous trace end pos horizontally in the move direction - trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, ms->entitynum); - //again this shouldn't happen - if (trace.startsolid) return qfalse; - // - VectorCopy(trace.endpos, start); - VectorCopy(trace.endpos, end); - end[2] = ms->origin[2]; - //trace down from the previous trace end pos - trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, ms->entitynum); - //if solid - if (trace.startsolid) return qfalse; - //if no obstacle at all - if (trace.fraction >= 1.0) return qfalse; - //if less than the maximum step height - if (trace.endpos[2] - ms->origin[2] < sv_maxstep->value) return qfalse; - // - EA_Jump(ms->client); - EA_Move(ms->client, hordir, speed); - ms->moveflags |= MFL_BARRIERJUMP; - //there is a barrier - return qtrue; -} //end of the function BotCheckBarrierJump -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotSwimInDirection(bot_movestate_t *ms, vec3_t dir, float speed, int type) -{ - vec3_t normdir; - - VectorCopy(dir, normdir); - VectorNormalize(normdir); - EA_Move(ms->client, normdir, speed); - return qtrue; -} //end of the function BotSwimInDirection -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotWalkInDirection(bot_movestate_t *ms, vec3_t dir, float speed, int type) -{ - vec3_t hordir, cmdmove, velocity, tmpdir, origin; - int presencetype, maxframes, cmdframes, stopevent; - aas_clientmove_t move; - float dist; - - if (AAS_OnGround(ms->origin, ms->presencetype, ms->entitynum)) ms->moveflags |= MFL_ONGROUND; - //if the bot is on the ground - if (ms->moveflags & MFL_ONGROUND) - { - //if there is a barrier the bot can jump on - if (BotCheckBarrierJump(ms, dir, speed)) return qtrue; - //remove barrier jump flag - ms->moveflags &= ~MFL_BARRIERJUMP; - //get the presence type for the movement - if ((type & MOVE_CROUCH) && !(type & MOVE_JUMP)) presencetype = PRESENCE_CROUCH; - else presencetype = PRESENCE_NORMAL; - //horizontal direction - hordir[0] = dir[0]; - hordir[1] = dir[1]; - hordir[2] = 0; - VectorNormalize(hordir); - //if the bot is not supposed to jump - if (!(type & MOVE_JUMP)) - { - //if there is a gap, try to jump over it - if (BotGapDistance(ms->origin, hordir, ms->entitynum) > 0) type |= MOVE_JUMP; - } //end if - //get command movement - VectorScale(hordir, speed, cmdmove); - VectorCopy(ms->velocity, velocity); - // - if (type & MOVE_JUMP) - { - //botimport.Print(PRT_MESSAGE, "trying jump\n"); - cmdmove[2] = 400; - maxframes = PREDICTIONTIME_JUMP / 0.1; - cmdframes = 1; - stopevent = SE_HITGROUND|SE_HITGROUNDDAMAGE| - SE_ENTERWATER|SE_ENTERSLIME|SE_ENTERLAVA; - } //end if - else - { - maxframes = 2; - cmdframes = 2; - stopevent = SE_HITGROUNDDAMAGE| - SE_ENTERWATER|SE_ENTERSLIME|SE_ENTERLAVA; - } //end else - //AAS_ClearShownDebugLines(); - // - VectorCopy(ms->origin, origin); - origin[2] += 0.5; - AAS_PredictClientMovement(&move, ms->entitynum, origin, presencetype, qtrue, - velocity, cmdmove, cmdframes, maxframes, 0.1f, - stopevent, 0, qfalse);//qtrue); - //if prediction time wasn't enough to fully predict the movement - if (move.frames >= maxframes && (type & MOVE_JUMP)) - { - //botimport.Print(PRT_MESSAGE, "client %d: max prediction frames\n", ms->client); - return qfalse; - } //end if - //don't enter slime or lava and don't fall from too high - if (move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA|SE_HITGROUNDDAMAGE)) - { - //botimport.Print(PRT_MESSAGE, "client %d: would be hurt ", ms->client); - //if (move.stopevent & SE_ENTERSLIME) botimport.Print(PRT_MESSAGE, "slime\n"); - //if (move.stopevent & SE_ENTERLAVA) botimport.Print(PRT_MESSAGE, "lava\n"); - //if (move.stopevent & SE_HITGROUNDDAMAGE) botimport.Print(PRT_MESSAGE, "hitground\n"); - return qfalse; - } //end if - //if ground was hit - if (move.stopevent & SE_HITGROUND) - { - //check for nearby gap - VectorNormalize2(move.velocity, tmpdir); - dist = BotGapDistance(move.endpos, tmpdir, ms->entitynum); - if (dist > 0) return qfalse; - // - dist = BotGapDistance(move.endpos, hordir, ms->entitynum); - if (dist > 0) return qfalse; - } //end if - //get horizontal movement - tmpdir[0] = move.endpos[0] - ms->origin[0]; - tmpdir[1] = move.endpos[1] - ms->origin[1]; - tmpdir[2] = 0; - // - //AAS_DrawCross(move.endpos, 4, LINECOLOR_BLUE); - //the bot is blocked by something - if (VectorLength(tmpdir) < speed * ms->thinktime * 0.5) return qfalse; - //perform the movement - if (type & MOVE_JUMP) EA_Jump(ms->client); - if (type & MOVE_CROUCH) EA_Crouch(ms->client); - EA_Move(ms->client, hordir, speed); - //movement was succesfull - return qtrue; - } //end if - else - { - if (ms->moveflags & MFL_BARRIERJUMP) - { - //if near the top or going down - if (ms->velocity[2] < 50) - { - EA_Move(ms->client, dir, speed); - } //end if - } //end if - //FIXME: do air control to avoid hazards - return qtrue; - } //end else -} //end of the function BotWalkInDirection -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotMoveInDirection(int movestate, vec3_t dir, float speed, int type) -{ - bot_movestate_t *ms; - - ms = BotMoveStateFromHandle(movestate); - if (!ms) return qfalse; - //if swimming - if (AAS_Swimming(ms->origin)) - { - return BotSwimInDirection(ms, dir, speed, type); - } //end if - else - { - return BotWalkInDirection(ms, dir, speed, type); - } //end else -} //end of the function BotMoveInDirection -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int Intersection(vec2_t p1, vec2_t p2, vec2_t p3, vec2_t p4, vec2_t out) -{ - float x1, dx1, dy1, x2, dx2, dy2, d; - - dx1 = p2[0] - p1[0]; - dy1 = p2[1] - p1[1]; - dx2 = p4[0] - p3[0]; - dy2 = p4[1] - p3[1]; - - d = dy1 * dx2 - dx1 * dy2; - if (d != 0) - { - x1 = p1[1] * dx1 - p1[0] * dy1; - x2 = p3[1] * dx2 - p3[0] * dy2; - out[0] = (int) ((dx1 * x2 - dx2 * x1) / d); - out[1] = (int) ((dy1 * x2 - dy2 * x1) / d); - return qtrue; - } //end if - else - { - return qfalse; - } //end else -} //end of the function Intersection -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotCheckBlocked(bot_movestate_t *ms, vec3_t dir, int checkbottom, bot_moveresult_t *result) -{ - vec3_t mins, maxs, end, up = {0, 0, 1}; - bsp_trace_t trace; - - //test for entities obstructing the bot's path - AAS_PresenceTypeBoundingBox(ms->presencetype, mins, maxs); - // - if (fabs(DotProduct(dir, up)) < 0.7) - { - mins[2] += sv_maxstep->value; //if the bot can step on - maxs[2] -= 10; //a little lower to avoid low ceiling - } //end if - VectorMA(ms->origin, 3, dir, end); - trace = AAS_Trace(ms->origin, mins, maxs, end, ms->entitynum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_BODY); - //if not started in solid and not hitting the world entity - if (!trace.startsolid && (trace.ent != ENTITYNUM_WORLD && trace.ent != ENTITYNUM_NONE) ) - { - result->blocked = qtrue; - result->blockentity = trace.ent; -#ifdef DEBUG - //botimport.Print(PRT_MESSAGE, "%d: BotCheckBlocked: I'm blocked\n", ms->client); -#endif //DEBUG - } //end if - //if not in an area with reachability - else if (checkbottom && !AAS_AreaReachability(ms->areanum)) - { - //check if the bot is standing on something - AAS_PresenceTypeBoundingBox(ms->presencetype, mins, maxs); - VectorMA(ms->origin, -3, up, end); - trace = AAS_Trace(ms->origin, mins, maxs, end, ms->entitynum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP); - if (!trace.startsolid && (trace.ent != ENTITYNUM_WORLD && trace.ent != ENTITYNUM_NONE) ) - { - result->blocked = qtrue; - result->blockentity = trace.ent; - result->flags |= MOVERESULT_ONTOPOFOBSTACLE; -#ifdef DEBUG - //botimport.Print(PRT_MESSAGE, "%d: BotCheckBlocked: I'm blocked\n", ms->client); -#endif //DEBUG - } //end if - } //end else -} //end of the function BotCheckBlocked -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_moveresult_t BotTravel_Walk(bot_movestate_t *ms, aas_reachability_t *reach) -{ - float dist, speed; - vec3_t hordir; - bot_moveresult_t_cleared( result ); - - //first walk straight to the reachability start - hordir[0] = reach->start[0] - ms->origin[0]; - hordir[1] = reach->start[1] - ms->origin[1]; - hordir[2] = 0; - dist = VectorNormalize(hordir); - // - BotCheckBlocked(ms, hordir, qtrue, &result); - // - if (dist < 10) - { - //walk straight to the reachability end - hordir[0] = reach->end[0] - ms->origin[0]; - hordir[1] = reach->end[1] - ms->origin[1]; - hordir[2] = 0; - dist = VectorNormalize(hordir); - } //end if - //if going towards a crouch area - if (!(AAS_AreaPresenceType(reach->areanum) & PRESENCE_NORMAL)) - { - //if pretty close to the reachable area - if (dist < 20) EA_Crouch(ms->client); - } //end if - // - dist = BotGapDistance(ms->origin, hordir, ms->entitynum); - // - if (ms->moveflags & MFL_WALK) - { - if (dist > 0) speed = 200 - (180 - 1 * dist); - else speed = 200; - EA_Walk(ms->client); - } //end if - else - { - if (dist > 0) speed = 400 - (360 - 2 * dist); - else speed = 400; - } //end else - //elemantary action move in direction - EA_Move(ms->client, hordir, speed); - VectorCopy(hordir, result.movedir); - // - return result; -} //end of the function BotTravel_Walk -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_moveresult_t BotFinishTravel_Walk(bot_movestate_t *ms, aas_reachability_t *reach) -{ - vec3_t hordir; - float dist, speed; - bot_moveresult_t_cleared( result ); - //if not on the ground and changed areas... don't walk back!! - //(doesn't seem to help) - /* - ms->areanum = BotFuzzyPointReachabilityArea(ms->origin); - if (ms->areanum == reach->areanum) - { -#ifdef DEBUG - botimport.Print(PRT_MESSAGE, "BotFinishTravel_Walk: already in reach area\n"); -#endif //DEBUG - return result; - } //end if*/ - //go straight to the reachability end - hordir[0] = reach->end[0] - ms->origin[0]; - hordir[1] = reach->end[1] - ms->origin[1]; - hordir[2] = 0; - dist = VectorNormalize(hordir); - // - if (dist > 100) dist = 100; - speed = 400 - (400 - 3 * dist); - // - EA_Move(ms->client, hordir, speed); - VectorCopy(hordir, result.movedir); - // - return result; -} //end of the function BotFinishTravel_Walk -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_moveresult_t BotTravel_Crouch(bot_movestate_t *ms, aas_reachability_t *reach) -{ - float speed; - vec3_t hordir; - bot_moveresult_t_cleared( result ); - - // - speed = 400; - //walk straight to reachability end - hordir[0] = reach->end[0] - ms->origin[0]; - hordir[1] = reach->end[1] - ms->origin[1]; - hordir[2] = 0; - VectorNormalize(hordir); - // - BotCheckBlocked(ms, hordir, qtrue, &result); - //elemantary actions - EA_Crouch(ms->client); - EA_Move(ms->client, hordir, speed); - // - VectorCopy(hordir, result.movedir); - // - return result; -} //end of the function BotTravel_Crouch -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_moveresult_t BotTravel_BarrierJump(bot_movestate_t *ms, aas_reachability_t *reach) -{ - float dist, speed; - vec3_t hordir; - bot_moveresult_t_cleared( result ); - - //walk straight to reachability start - hordir[0] = reach->start[0] - ms->origin[0]; - hordir[1] = reach->start[1] - ms->origin[1]; - hordir[2] = 0; - dist = VectorNormalize(hordir); - // - BotCheckBlocked(ms, hordir, qtrue, &result); - //if pretty close to the barrier - if (dist < 9) - { - EA_Jump(ms->client); - } //end if - else - { - if (dist > 60) dist = 60; - speed = 360 - (360 - 6 * dist); - EA_Move(ms->client, hordir, speed); - } //end else - VectorCopy(hordir, result.movedir); - // - return result; -} //end of the function BotTravel_BarrierJump -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_moveresult_t BotFinishTravel_BarrierJump(bot_movestate_t *ms, aas_reachability_t *reach) -{ - float dist; - vec3_t hordir; - bot_moveresult_t_cleared( result ); - - //if near the top or going down - if (ms->velocity[2] < 250) - { - hordir[0] = reach->end[0] - ms->origin[0]; - hordir[1] = reach->end[1] - ms->origin[1]; - hordir[2] = 0; - dist = VectorNormalize(hordir); - // - BotCheckBlocked(ms, hordir, qtrue, &result); - // - EA_Move(ms->client, hordir, 400); - VectorCopy(hordir, result.movedir); - } //end if - // - return result; -} //end of the function BotFinishTravel_BarrierJump -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_moveresult_t BotTravel_Swim(bot_movestate_t *ms, aas_reachability_t *reach) -{ - vec3_t dir; - bot_moveresult_t_cleared( result ); - - //swim straight to reachability end - VectorSubtract(reach->start, ms->origin, dir); - VectorNormalize(dir); - // - BotCheckBlocked(ms, dir, qtrue, &result); - //elemantary actions - EA_Move(ms->client, dir, 400); - // - VectorCopy(dir, result.movedir); - Vector2Angles(dir, result.ideal_viewangles); - result.flags |= MOVERESULT_SWIMVIEW; - // - return result; -} //end of the function BotTravel_Swim -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_moveresult_t BotTravel_WaterJump(bot_movestate_t *ms, aas_reachability_t *reach) -{ - vec3_t dir, hordir; - float dist; - bot_moveresult_t_cleared( result ); - - //swim straight to reachability end - VectorSubtract(reach->end, ms->origin, dir); - VectorCopy(dir, hordir); - hordir[2] = 0; - dir[2] += 15 + crandom() * 40; - //botimport.Print(PRT_MESSAGE, "BotTravel_WaterJump: dir[2] = %f\n", dir[2]); - VectorNormalize(dir); - dist = VectorNormalize(hordir); - //elemantary actions - //EA_Move(ms->client, dir, 400); - EA_MoveForward(ms->client); - //move up if close to the actual out of water jump spot - if (dist < 40) EA_MoveUp(ms->client); - //set the ideal view angles - Vector2Angles(dir, result.ideal_viewangles); - result.flags |= MOVERESULT_MOVEMENTVIEW; - // - VectorCopy(dir, result.movedir); - // - return result; -} //end of the function BotTravel_WaterJump -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_moveresult_t BotFinishTravel_WaterJump(bot_movestate_t *ms, aas_reachability_t *reach) -{ - vec3_t dir, pnt; - float dist; - bot_moveresult_t_cleared( result ); - - //botimport.Print(PRT_MESSAGE, "BotFinishTravel_WaterJump\n"); - //if waterjumping there's nothing to do - if (ms->moveflags & MFL_WATERJUMP) return result; - //if not touching any water anymore don't do anything - //otherwise the bot sometimes keeps jumping? - VectorCopy(ms->origin, pnt); - pnt[2] -= 32; //extra for q2dm4 near red armor/mega health - if (!(AAS_PointContents(pnt) & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER))) return result; - //swim straight to reachability end - VectorSubtract(reach->end, ms->origin, dir); - dir[0] += crandom() * 10; - dir[1] += crandom() * 10; - dir[2] += 70 + crandom() * 10; - dist = VectorNormalize(dir); - //elemantary actions - EA_Move(ms->client, dir, 400); - //set the ideal view angles - Vector2Angles(dir, result.ideal_viewangles); - result.flags |= MOVERESULT_MOVEMENTVIEW; - // - VectorCopy(dir, result.movedir); - // - return result; -} //end of the function BotFinishTravel_WaterJump -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_moveresult_t BotTravel_WalkOffLedge(bot_movestate_t *ms, aas_reachability_t *reach) -{ - vec3_t hordir, dir; - float dist, speed, reachhordist; - bot_moveresult_t_cleared( result ); - - //check if the bot is blocked by anything - VectorSubtract(reach->start, ms->origin, dir); - VectorNormalize(dir); - BotCheckBlocked(ms, dir, qtrue, &result); - //if the reachability start and end are practially above each other - VectorSubtract(reach->end, reach->start, dir); - dir[2] = 0; - reachhordist = VectorLength(dir); - //walk straight to the reachability start - hordir[0] = reach->start[0] - ms->origin[0]; - hordir[1] = reach->start[1] - ms->origin[1]; - hordir[2] = 0; - dist = VectorNormalize(hordir); - //if pretty close to the start focus on the reachability end - if (dist < 48) - { - hordir[0] = reach->end[0] - ms->origin[0]; - hordir[1] = reach->end[1] - ms->origin[1]; - hordir[2] = 0; - VectorNormalize(hordir); - // - if (reachhordist < 20) - { - speed = 100; - } //end if - else if (!AAS_HorizontalVelocityForJump(0, reach->start, reach->end, &speed)) - { - speed = 400; - } //end if - } //end if - else - { - if (reachhordist < 20) - { - if (dist > 64) dist = 64; - speed = 400 - (256 - 4 * dist); - } //end if - else - { - speed = 400; - } //end else - } //end else - // - BotCheckBlocked(ms, hordir, qtrue, &result); - //elemantary action - EA_Move(ms->client, hordir, speed); - VectorCopy(hordir, result.movedir); - // - return result; -} //end of the function BotTravel_WalkOffLedge -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotAirControl(vec3_t origin, vec3_t velocity, vec3_t goal, vec3_t dir, float *speed) -{ - vec3_t org, vel; - float dist; - int i; - - VectorCopy(origin, org); - VectorScale(velocity, 0.1, vel); - for (i = 0; i < 50; i++) - { - vel[2] -= sv_gravity->value * 0.01; - //if going down and next position would be below the goal - if (vel[2] < 0 && org[2] + vel[2] < goal[2]) - { - VectorScale(vel, (goal[2] - org[2]) / vel[2], vel); - VectorAdd(org, vel, org); - VectorSubtract(goal, org, dir); - dist = VectorNormalize(dir); - if (dist > 32) dist = 32; - *speed = 400 - (400 - 13 * dist); - return qtrue; - } //end if - else - { - VectorAdd(org, vel, org); - } //end else - } //end for - VectorSet(dir, 0, 0, 0); - *speed = 400; - return qfalse; -} //end of the function BotAirControl -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_moveresult_t BotFinishTravel_WalkOffLedge(bot_movestate_t *ms, aas_reachability_t *reach) -{ - vec3_t dir, hordir, end, v; - float dist, speed; - bot_moveresult_t_cleared( result ); - - // - VectorSubtract(reach->end, ms->origin, dir); - BotCheckBlocked(ms, dir, qtrue, &result); - // - VectorSubtract(reach->end, ms->origin, v); - v[2] = 0; - dist = VectorNormalize(v); - if (dist > 16) VectorMA(reach->end, 16, v, end); - else VectorCopy(reach->end, end); - // - if (!BotAirControl(ms->origin, ms->velocity, end, hordir, &speed)) - { - //go straight to the reachability end - VectorCopy(dir, hordir); - hordir[2] = 0; - // - dist = VectorNormalize(hordir); - speed = 400; - } //end if - // - EA_Move(ms->client, hordir, speed); - VectorCopy(hordir, result.movedir); - // - return result; -} //end of the function BotFinishTravel_WalkOffLedge -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -/* -bot_moveresult_t BotTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach) -{ - vec3_t hordir; - float dist, gapdist, speed, horspeed, sv_jumpvel; - bot_moveresult_t_cleared( result ); - - // - sv_jumpvel = botlibglobals.sv_jumpvel->value; - //walk straight to the reachability start - hordir[0] = reach->start[0] - ms->origin[0]; - hordir[1] = reach->start[1] - ms->origin[1]; - hordir[2] = 0; - dist = VectorNormalize(hordir); - // - speed = 350; - // - gapdist = BotGapDistance(ms, hordir, ms->entitynum); - //if pretty close to the start focus on the reachability end - if (dist < 50 || (gapdist && gapdist < 50)) - { - //NOTE: using max speed (400) works best - //if (AAS_HorizontalVelocityForJump(sv_jumpvel, ms->origin, reach->end, &horspeed)) - //{ - // speed = horspeed * 400 / botlibglobals.sv_maxwalkvelocity->value; - //} //end if - hordir[0] = reach->end[0] - ms->origin[0]; - hordir[1] = reach->end[1] - ms->origin[1]; - VectorNormalize(hordir); - //elemantary action jump - EA_Jump(ms->client); - // - ms->jumpreach = ms->lastreachnum; - speed = 600; - } //end if - else - { - if (AAS_HorizontalVelocityForJump(sv_jumpvel, reach->start, reach->end, &horspeed)) - { - speed = horspeed * 400 / botlibglobals.sv_maxwalkvelocity->value; - } //end if - } //end else - //elemantary action - EA_Move(ms->client, hordir, speed); - VectorCopy(hordir, result.movedir); - // - return result; -} //end of the function BotTravel_Jump*/ -/* -bot_moveresult_t BotTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach) -{ - vec3_t hordir, dir1, dir2, mins, maxs, start, end; - float dist1, dist2, speed; - bot_moveresult_t_cleared( result ); - bsp_trace_t trace; - - // - hordir[0] = reach->start[0] - reach->end[0]; - hordir[1] = reach->start[1] - reach->end[1]; - hordir[2] = 0; - VectorNormalize(hordir); - // - VectorCopy(reach->start, start); - start[2] += 1; - //minus back the bouding box size plus 16 - VectorMA(reach->start, 80, hordir, end); - // - AAS_PresenceTypeBoundingBox(PRESENCE_NORMAL, mins, maxs); - //check for solids - trace = AAS_Trace(start, mins, maxs, end, ms->entitynum, MASK_PLAYERSOLID); - if (trace.startsolid) VectorCopy(start, trace.endpos); - //check for a gap - for (dist1 = 0; dist1 < 80; dist1 += 10) - { - VectorMA(start, dist1+10, hordir, end); - end[2] += 1; - if (AAS_PointAreaNum(end) != ms->reachareanum) break; - } //end for - if (dist1 < 80) VectorMA(reach->start, dist1, hordir, trace.endpos); -// dist1 = BotGapDistance(start, hordir, ms->entitynum); -// if (dist1 && dist1 <= trace.fraction * 80) VectorMA(reach->start, dist1-20, hordir, trace.endpos); - // - VectorSubtract(ms->origin, reach->start, dir1); - dir1[2] = 0; - dist1 = VectorNormalize(dir1); - VectorSubtract(ms->origin, trace.endpos, dir2); - dir2[2] = 0; - dist2 = VectorNormalize(dir2); - //if just before the reachability start - if (DotProduct(dir1, dir2) < -0.8 || dist2 < 5) - { - //botimport.Print(PRT_MESSAGE, "between jump start and run to point\n"); - hordir[0] = reach->end[0] - ms->origin[0]; - hordir[1] = reach->end[1] - ms->origin[1]; - hordir[2] = 0; - VectorNormalize(hordir); - //elemantary action jump - if (dist1 < 24) EA_Jump(ms->client); - else if (dist1 < 32) EA_DelayedJump(ms->client); - EA_Move(ms->client, hordir, 600); - // - ms->jumpreach = ms->lastreachnum; - } //end if - else - { - //botimport.Print(PRT_MESSAGE, "going towards run to point\n"); - hordir[0] = trace.endpos[0] - ms->origin[0]; - hordir[1] = trace.endpos[1] - ms->origin[1]; - hordir[2] = 0; - VectorNormalize(hordir); - // - if (dist2 > 80) dist2 = 80; - speed = 400 - (400 - 5 * dist2); - EA_Move(ms->client, hordir, speed); - } //end else - VectorCopy(hordir, result.movedir); - // - return result; -} //end of the function BotTravel_Jump*/ -//* -bot_moveresult_t BotTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach) -{ - vec3_t hordir, dir1, dir2, start, end, runstart; -// vec3_t runstart, dir1, dir2, hordir; - float dist1, dist2, speed; - bot_moveresult_t_cleared( result ); - - // - AAS_JumpReachRunStart(reach, runstart); - //* - hordir[0] = runstart[0] - reach->start[0]; - hordir[1] = runstart[1] - reach->start[1]; - hordir[2] = 0; - VectorNormalize(hordir); - // - VectorCopy(reach->start, start); - start[2] += 1; - VectorMA(reach->start, 80, hordir, runstart); - //check for a gap - for (dist1 = 0; dist1 < 80; dist1 += 10) - { - VectorMA(start, dist1+10, hordir, end); - end[2] += 1; - if (AAS_PointAreaNum(end) != ms->reachareanum) break; - } //end for - if (dist1 < 80) VectorMA(reach->start, dist1, hordir, runstart); - // - VectorSubtract(ms->origin, reach->start, dir1); - dir1[2] = 0; - dist1 = VectorNormalize(dir1); - VectorSubtract(ms->origin, runstart, dir2); - dir2[2] = 0; - dist2 = VectorNormalize(dir2); - //if just before the reachability start - if (DotProduct(dir1, dir2) < -0.8 || dist2 < 5) - { -// botimport.Print(PRT_MESSAGE, "between jump start and run start point\n"); - hordir[0] = reach->end[0] - ms->origin[0]; - hordir[1] = reach->end[1] - ms->origin[1]; - hordir[2] = 0; - VectorNormalize(hordir); - //elemantary action jump - if (dist1 < 24) EA_Jump(ms->client); - else if (dist1 < 32) EA_DelayedJump(ms->client); - EA_Move(ms->client, hordir, 600); - // - ms->jumpreach = ms->lastreachnum; - } //end if - else - { -// botimport.Print(PRT_MESSAGE, "going towards run start point\n"); - hordir[0] = runstart[0] - ms->origin[0]; - hordir[1] = runstart[1] - ms->origin[1]; - hordir[2] = 0; - VectorNormalize(hordir); - // - if (dist2 > 80) dist2 = 80; - speed = 400 - (400 - 5 * dist2); - EA_Move(ms->client, hordir, speed); - } //end else - VectorCopy(hordir, result.movedir); - // - return result; -} //end of the function BotTravel_Jump*/ -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_moveresult_t BotFinishTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach) -{ - vec3_t hordir, hordir2; - float speed, dist; - bot_moveresult_t_cleared( result ); - - //if not jumped yet - if (!ms->jumpreach) return result; - //go straight to the reachability end - hordir[0] = reach->end[0] - ms->origin[0]; - hordir[1] = reach->end[1] - ms->origin[1]; - hordir[2] = 0; - dist = VectorNormalize(hordir); - // - hordir2[0] = reach->end[0] - reach->start[0]; - hordir2[1] = reach->end[1] - reach->start[1]; - hordir2[2] = 0; - VectorNormalize(hordir2); - // - if (DotProduct(hordir, hordir2) < -0.5 && dist < 24) return result; - //always use max speed when traveling through the air - speed = 800; - // - EA_Move(ms->client, hordir, speed); - VectorCopy(hordir, result.movedir); - // - return result; -} //end of the function BotFinishTravel_Jump -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_moveresult_t BotTravel_Ladder(bot_movestate_t *ms, aas_reachability_t *reach) -{ - //float dist, speed; - vec3_t dir, viewdir;//, hordir; - vec3_t origin = {0, 0, 0}; -// vec3_t up = {0, 0, 1}; - bot_moveresult_t_cleared( result ); - - // -// if ((ms->moveflags & MFL_AGAINSTLADDER)) - //NOTE: not a good idea for ladders starting in water - // || !(ms->moveflags & MFL_ONGROUND)) - { - //botimport.Print(PRT_MESSAGE, "against ladder or not on ground\n"); - VectorSubtract(reach->end, ms->origin, dir); - VectorNormalize(dir); - //set the ideal view angles, facing the ladder up or down - viewdir[0] = dir[0]; - viewdir[1] = dir[1]; - viewdir[2] = 3 * dir[2]; - Vector2Angles(viewdir, result.ideal_viewangles); - //elemantary action - EA_Move(ms->client, origin, 0); - EA_MoveForward(ms->client); - //set movement view flag so the AI can see the view is focussed - result.flags |= MOVERESULT_MOVEMENTVIEW; - } //end if -/* else - { - //botimport.Print(PRT_MESSAGE, "moving towards ladder\n"); - VectorSubtract(reach->end, ms->origin, dir); - //make sure the horizontal movement is large anough - VectorCopy(dir, hordir); - hordir[2] = 0; - dist = VectorNormalize(hordir); - // - dir[0] = hordir[0]; - dir[1] = hordir[1]; - if (dir[2] > 0) dir[2] = 1; - else dir[2] = -1; - if (dist > 50) dist = 50; - speed = 400 - (200 - 4 * dist); - EA_Move(ms->client, dir, speed); - } //end else*/ - //save the movement direction - VectorCopy(dir, result.movedir); - // - return result; -} //end of the function BotTravel_Ladder -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_moveresult_t BotTravel_Teleport(bot_movestate_t *ms, aas_reachability_t *reach) -{ - vec3_t hordir; - float dist; - bot_moveresult_t_cleared( result ); - - //if the bot is being teleported - if (ms->moveflags & MFL_TELEPORTED) return result; - - //walk straight to center of the teleporter - VectorSubtract(reach->start, ms->origin, hordir); - if (!(ms->moveflags & MFL_SWIMMING)) hordir[2] = 0; - dist = VectorNormalize(hordir); - // - BotCheckBlocked(ms, hordir, qtrue, &result); - - if (dist < 30) EA_Move(ms->client, hordir, 200); - else EA_Move(ms->client, hordir, 400); - - if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW; - - VectorCopy(hordir, result.movedir); - return result; -} //end of the function BotTravel_Teleport -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_moveresult_t BotTravel_Elevator(bot_movestate_t *ms, aas_reachability_t *reach) -{ - vec3_t dir, dir1, dir2, hordir, bottomcenter; - float dist, dist1, dist2, speed; - bot_moveresult_t_cleared( result ); - - //if standing on the plat - if (BotOnMover(ms->origin, ms->entitynum, reach)) - { -#ifdef DEBUG_ELEVATOR - botimport.Print(PRT_MESSAGE, "bot on elevator\n"); -#endif //DEBUG_ELEVATOR - //if vertically not too far from the end point - if (abs(ms->origin[2] - reach->end[2]) < sv_maxbarrier->value) - { -#ifdef DEBUG_ELEVATOR - botimport.Print(PRT_MESSAGE, "bot moving to end\n"); -#endif //DEBUG_ELEVATOR - //move to the end point - VectorSubtract(reach->end, ms->origin, hordir); - hordir[2] = 0; - VectorNormalize(hordir); - if (!BotCheckBarrierJump(ms, hordir, 100)) - { - EA_Move(ms->client, hordir, 400); - } //end if - VectorCopy(hordir, result.movedir); - } //end else - //if not really close to the center of the elevator - else - { - MoverBottomCenter(reach, bottomcenter); - VectorSubtract(bottomcenter, ms->origin, hordir); - hordir[2] = 0; - dist = VectorNormalize(hordir); - // - if (dist > 10) - { -#ifdef DEBUG_ELEVATOR - botimport.Print(PRT_MESSAGE, "bot moving to center\n"); -#endif //DEBUG_ELEVATOR - //move to the center of the plat - if (dist > 100) dist = 100; - speed = 400 - (400 - 4 * dist); - // - EA_Move(ms->client, hordir, speed); - VectorCopy(hordir, result.movedir); - } //end if - } //end else - } //end if - else - { -#ifdef DEBUG_ELEVATOR - botimport.Print(PRT_MESSAGE, "bot not on elevator\n"); -#endif //DEBUG_ELEVATOR - //if very near the reachability end - VectorSubtract(reach->end, ms->origin, dir); - dist = VectorLength(dir); - if (dist < 64) - { - if (dist > 60) dist = 60; - speed = 360 - (360 - 6 * dist); - // - if ((ms->moveflags & MFL_SWIMMING) || !BotCheckBarrierJump(ms, dir, 50)) - { - if (speed > 5) EA_Move(ms->client, dir, speed); - } //end if - VectorCopy(dir, result.movedir); - // - if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW; - //stop using this reachability - ms->reachability_time = 0; - return result; - } //end if - //get direction and distance to reachability start - VectorSubtract(reach->start, ms->origin, dir1); - if (!(ms->moveflags & MFL_SWIMMING)) dir1[2] = 0; - dist1 = VectorNormalize(dir1); - //if the elevator isn't down - if (!MoverDown(reach)) - { -#ifdef DEBUG_ELEVATOR - botimport.Print(PRT_MESSAGE, "elevator not down\n"); -#endif //DEBUG_ELEVATOR - dist = dist1; - VectorCopy(dir1, dir); - // - BotCheckBlocked(ms, dir, qfalse, &result); - // - if (dist > 60) dist = 60; - speed = 360 - (360 - 6 * dist); - // - if (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50)) - { - if (speed > 5) EA_Move(ms->client, dir, speed); - } //end if - VectorCopy(dir, result.movedir); - // - if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW; - //this isn't a failure... just wait till the elevator comes down - result.type = RESULTTYPE_ELEVATORUP; - result.flags |= MOVERESULT_WAITING; - return result; - } //end if - //get direction and distance to elevator bottom center - MoverBottomCenter(reach, bottomcenter); - VectorSubtract(bottomcenter, ms->origin, dir2); - if (!(ms->moveflags & MFL_SWIMMING)) dir2[2] = 0; - dist2 = VectorNormalize(dir2); - //if very close to the reachability start or - //closer to the elevator center or - //between reachability start and elevator center - if (dist1 < 20 || dist2 < dist1 || DotProduct(dir1, dir2) < 0) - { -#ifdef DEBUG_ELEVATOR - botimport.Print(PRT_MESSAGE, "bot moving to center\n"); -#endif //DEBUG_ELEVATOR - dist = dist2; - VectorCopy(dir2, dir); - } //end if - else //closer to the reachability start - { -#ifdef DEBUG_ELEVATOR - botimport.Print(PRT_MESSAGE, "bot moving to start\n"); -#endif //DEBUG_ELEVATOR - dist = dist1; - VectorCopy(dir1, dir); - } //end else - // - BotCheckBlocked(ms, dir, qfalse, &result); - // - if (dist > 60) dist = 60; - speed = 400 - (400 - 6 * dist); - // - if (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50)) - { - EA_Move(ms->client, dir, speed); - } //end if - VectorCopy(dir, result.movedir); - // - if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW; - } //end else - return result; -} //end of the function BotTravel_Elevator -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_moveresult_t BotFinishTravel_Elevator(bot_movestate_t *ms, aas_reachability_t *reach) -{ - vec3_t bottomcenter, bottomdir, topdir; - bot_moveresult_t_cleared( result ); - - // - MoverBottomCenter(reach, bottomcenter); - VectorSubtract(bottomcenter, ms->origin, bottomdir); - // - VectorSubtract(reach->end, ms->origin, topdir); - // - if (fabs(bottomdir[2]) < fabs(topdir[2])) - { - VectorNormalize(bottomdir); - EA_Move(ms->client, bottomdir, 300); - } //end if - else - { - VectorNormalize(topdir); - EA_Move(ms->client, topdir, 300); - } //end else - return result; -} //end of the function BotFinishTravel_Elevator -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotFuncBobStartEnd(aas_reachability_t *reach, vec3_t start, vec3_t end, vec3_t origin) -{ - int spawnflags, modelnum; - vec3_t mins, maxs, mid, angles = {0, 0, 0}; - int num0, num1; - - modelnum = reach->facenum & 0x0000FFFF; - if (!AAS_OriginOfMoverWithModelNum(modelnum, origin)) - { - botimport.Print(PRT_MESSAGE, "BotFuncBobStartEnd: no entity with model %d\n", modelnum); - VectorSet(start, 0, 0, 0); - VectorSet(end, 0, 0, 0); - return; - } //end if - AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, NULL); - VectorAdd(mins, maxs, mid); - VectorScale(mid, 0.5, mid); - VectorCopy(mid, start); - VectorCopy(mid, end); - spawnflags = reach->facenum >> 16; - num0 = reach->edgenum >> 16; - if (num0 > 0x00007FFF) num0 |= 0xFFFF0000; - num1 = reach->edgenum & 0x0000FFFF; - if (num1 > 0x00007FFF) num1 |= 0xFFFF0000; - if (spawnflags & 1) - { - start[0] = num0; - end[0] = num1; - // - origin[0] += mid[0]; - origin[1] = mid[1]; - origin[2] = mid[2]; - } //end if - else if (spawnflags & 2) - { - start[1] = num0; - end[1] = num1; - // - origin[0] = mid[0]; - origin[1] += mid[1]; - origin[2] = mid[2]; - } //end else if - else - { - start[2] = num0; - end[2] = num1; - // - origin[0] = mid[0]; - origin[1] = mid[1]; - origin[2] += mid[2]; - } //end else -} //end of the function BotFuncBobStartEnd -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_moveresult_t BotTravel_FuncBobbing(bot_movestate_t *ms, aas_reachability_t *reach) -{ - vec3_t dir, dir1, dir2, hordir, bottomcenter, bob_start, bob_end, bob_origin; - float dist, dist1, dist2, speed; - bot_moveresult_t_cleared( result ); - - // - BotFuncBobStartEnd(reach, bob_start, bob_end, bob_origin); - //if standing ontop of the func_bobbing - if (BotOnMover(ms->origin, ms->entitynum, reach)) - { -#ifdef DEBUG_FUNCBOB - botimport.Print(PRT_MESSAGE, "bot on func_bobbing\n"); -#endif - //if near end point of reachability - VectorSubtract(bob_origin, bob_end, dir); - if (VectorLength(dir) < 24) - { -#ifdef DEBUG_FUNCBOB - botimport.Print(PRT_MESSAGE, "bot moving to reachability end\n"); -#endif - //move to the end point - VectorSubtract(reach->end, ms->origin, hordir); - hordir[2] = 0; - VectorNormalize(hordir); - if (!BotCheckBarrierJump(ms, hordir, 100)) - { - EA_Move(ms->client, hordir, 400); - } //end if - VectorCopy(hordir, result.movedir); - } //end else - //if not really close to the center of the elevator - else - { - MoverBottomCenter(reach, bottomcenter); - VectorSubtract(bottomcenter, ms->origin, hordir); - hordir[2] = 0; - dist = VectorNormalize(hordir); - // - if (dist > 10) - { -#ifdef DEBUG_FUNCBOB - botimport.Print(PRT_MESSAGE, "bot moving to func_bobbing center\n"); -#endif - //move to the center of the plat - if (dist > 100) dist = 100; - speed = 400 - (400 - 4 * dist); - // - EA_Move(ms->client, hordir, speed); - VectorCopy(hordir, result.movedir); - } //end if - } //end else - } //end if - else - { -#ifdef DEBUG_FUNCBOB - botimport.Print(PRT_MESSAGE, "bot not ontop of func_bobbing\n"); -#endif - //if very near the reachability end - VectorSubtract(reach->end, ms->origin, dir); - dist = VectorLength(dir); - if (dist < 64) - { -#ifdef DEBUG_FUNCBOB - botimport.Print(PRT_MESSAGE, "bot moving to end\n"); -#endif - if (dist > 60) dist = 60; - speed = 360 - (360 - 6 * dist); - //if swimming or no barrier jump - if ((ms->moveflags & MFL_SWIMMING) || !BotCheckBarrierJump(ms, dir, 50)) - { - if (speed > 5) EA_Move(ms->client, dir, speed); - } //end if - VectorCopy(dir, result.movedir); - // - if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW; - //stop using this reachability - ms->reachability_time = 0; - return result; - } //end if - //get direction and distance to reachability start - VectorSubtract(reach->start, ms->origin, dir1); - if (!(ms->moveflags & MFL_SWIMMING)) dir1[2] = 0; - dist1 = VectorNormalize(dir1); - //if func_bobbing is Not it's start position - VectorSubtract(bob_origin, bob_start, dir); - if (VectorLength(dir) > 16) - { -#ifdef DEBUG_FUNCBOB - botimport.Print(PRT_MESSAGE, "func_bobbing not at start\n"); -#endif - dist = dist1; - VectorCopy(dir1, dir); - // - BotCheckBlocked(ms, dir, qfalse, &result); - // - if (dist > 60) dist = 60; - speed = 360 - (360 - 6 * dist); - // - if (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50)) - { - if (speed > 5) EA_Move(ms->client, dir, speed); - } //end if - VectorCopy(dir, result.movedir); - // - if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW; - //this isn't a failure... just wait till the func_bobbing arrives - result.type = RESULTTYPE_WAITFORFUNCBOBBING; - result.flags |= MOVERESULT_WAITING; - return result; - } //end if - //get direction and distance to func_bob bottom center - MoverBottomCenter(reach, bottomcenter); - VectorSubtract(bottomcenter, ms->origin, dir2); - if (!(ms->moveflags & MFL_SWIMMING)) dir2[2] = 0; - dist2 = VectorNormalize(dir2); - //if very close to the reachability start or - //closer to the elevator center or - //between reachability start and func_bobbing center - if (dist1 < 20 || dist2 < dist1 || DotProduct(dir1, dir2) < 0) - { -#ifdef DEBUG_FUNCBOB - botimport.Print(PRT_MESSAGE, "bot moving to func_bobbing center\n"); -#endif - dist = dist2; - VectorCopy(dir2, dir); - } //end if - else //closer to the reachability start - { -#ifdef DEBUG_FUNCBOB - botimport.Print(PRT_MESSAGE, "bot moving to reachability start\n"); -#endif - dist = dist1; - VectorCopy(dir1, dir); - } //end else - // - BotCheckBlocked(ms, dir, qfalse, &result); - // - if (dist > 60) dist = 60; - speed = 400 - (400 - 6 * dist); - // - if (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50)) - { - EA_Move(ms->client, dir, speed); - } //end if - VectorCopy(dir, result.movedir); - // - if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW; - } //end else - return result; -} //end of the function BotTravel_FuncBobbing -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_moveresult_t BotFinishTravel_FuncBobbing(bot_movestate_t *ms, aas_reachability_t *reach) -{ - vec3_t bob_origin, bob_start, bob_end, dir, hordir, bottomcenter; - bot_moveresult_t_cleared( result ); - float dist, speed; - - // - BotFuncBobStartEnd(reach, bob_start, bob_end, bob_origin); - // - VectorSubtract(bob_origin, bob_end, dir); - dist = VectorLength(dir); - //if the func_bobbing is near the end - if (dist < 16) - { - VectorSubtract(reach->end, ms->origin, hordir); - if (!(ms->moveflags & MFL_SWIMMING)) hordir[2] = 0; - dist = VectorNormalize(hordir); - // - if (dist > 60) dist = 60; - speed = 360 - (360 - 6 * dist); - // - if (speed > 5) EA_Move(ms->client, dir, speed); - VectorCopy(dir, result.movedir); - // - if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW; - } //end if - else - { - MoverBottomCenter(reach, bottomcenter); - VectorSubtract(bottomcenter, ms->origin, hordir); - if (!(ms->moveflags & MFL_SWIMMING)) hordir[2] = 0; - dist = VectorNormalize(hordir); - // - if (dist > 5) - { - //move to the center of the plat - if (dist > 100) dist = 100; - speed = 400 - (400 - 4 * dist); - // - EA_Move(ms->client, hordir, speed); - VectorCopy(hordir, result.movedir); - } //end if - } //end else - return result; -} //end of the function BotFinishTravel_FuncBobbing -//=========================================================================== -// 0 no valid grapple hook visible -// 1 the grapple hook is still flying -// 2 the grapple hooked into a wall -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int GrappleState(bot_movestate_t *ms, aas_reachability_t *reach) -{ - int i; - aas_entityinfo_t entinfo; - - //if the grapple hook is pulling - if (ms->moveflags & MFL_GRAPPLEPULL) - return 2; - //check for a visible grapple missile entity - //or visible grapple entity - for (i = AAS_NextEntity(0); i; i = AAS_NextEntity(i)) - { - if (AAS_EntityType(i) == (int) entitytypemissile->value) - { - AAS_EntityInfo(i, &entinfo); - if (entinfo.weapon == (int) weapindex_grapple->value) - { - return 1; - } //end if - } //end if - } //end for - //no valid grapple at all - return 0; -} //end of the function GrappleState -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotResetGrapple(bot_movestate_t *ms) -{ - aas_reachability_t reach; - - AAS_ReachabilityFromNum(ms->lastreachnum, &reach); - //if not using the grapple hook reachability anymore - if ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_GRAPPLEHOOK) - { - if ((ms->moveflags & MFL_ACTIVEGRAPPLE) || ms->grapplevisible_time) - { - if (offhandgrapple->value) - EA_Command(ms->client, cmd_grappleoff->string); - ms->moveflags &= ~MFL_ACTIVEGRAPPLE; - ms->grapplevisible_time = 0; -#ifdef DEBUG_GRAPPLE - botimport.Print(PRT_MESSAGE, "reset grapple\n"); -#endif //DEBUG_GRAPPLE - } //end if - } //end if -} //end of the function BotResetGrapple -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_moveresult_t BotTravel_Grapple(bot_movestate_t *ms, aas_reachability_t *reach) -{ - bot_moveresult_t_cleared( result ); - float dist, speed; - vec3_t dir, viewdir, org; - int state, areanum; - bsp_trace_t trace; - -#ifdef DEBUG_GRAPPLE - static int debugline; - if (!debugline) debugline = botimport.DebugLineCreate(); - botimport.DebugLineShow(debugline, reach->start, reach->end, LINECOLOR_BLUE); -#endif //DEBUG_GRAPPLE - - // - if (ms->moveflags & MFL_GRAPPLERESET) - { - if (offhandgrapple->value) - EA_Command(ms->client, cmd_grappleoff->string); - ms->moveflags &= ~MFL_ACTIVEGRAPPLE; - return result; - } //end if - // - if (!(int) offhandgrapple->value) - { - result.weapon = weapindex_grapple->value; - result.flags |= MOVERESULT_MOVEMENTWEAPON; - } //end if - // - if (ms->moveflags & MFL_ACTIVEGRAPPLE) - { -#ifdef DEBUG_GRAPPLE - botimport.Print(PRT_MESSAGE, "BotTravel_Grapple: active grapple\n"); -#endif //DEBUG_GRAPPLE - // - state = GrappleState(ms, reach); - // - VectorSubtract(reach->end, ms->origin, dir); - dir[2] = 0; - dist = VectorLength(dir); - //if very close to the grapple end or the grappled is hooked and - //the bot doesn't get any closer - if (state && dist < 48) - { - if (ms->lastgrappledist - dist < 1) - { -#ifdef DEBUG_GRAPPLE - botimport.Print(PRT_ERROR, "grapple normal end\n"); -#endif //DEBUG_GRAPPLE - if (offhandgrapple->value) - EA_Command(ms->client, cmd_grappleoff->string); - ms->moveflags &= ~MFL_ACTIVEGRAPPLE; - ms->moveflags |= MFL_GRAPPLERESET; - ms->reachability_time = 0; //end the reachability - return result; - } //end if - } //end if - //if no valid grapple at all, or the grapple hooked and the bot - //isn't moving anymore - else if (!state || (state == 2 && dist > ms->lastgrappledist - 2)) - { - if (ms->grapplevisible_time < AAS_Time() - 0.4) - { -#ifdef DEBUG_GRAPPLE - botimport.Print(PRT_ERROR, "grapple not visible\n"); -#endif //DEBUG_GRAPPLE - if (offhandgrapple->value) - EA_Command(ms->client, cmd_grappleoff->string); - ms->moveflags &= ~MFL_ACTIVEGRAPPLE; - ms->moveflags |= MFL_GRAPPLERESET; - ms->reachability_time = 0; //end the reachability - return result; - } //end if - } //end if - else - { - ms->grapplevisible_time = AAS_Time(); - } //end else - // - if (!(int) offhandgrapple->value) - { - EA_Attack(ms->client); - } //end if - //remember the current grapple distance - ms->lastgrappledist = dist; - } //end if - else - { -#ifdef DEBUG_GRAPPLE - botimport.Print(PRT_MESSAGE, "BotTravel_Grapple: inactive grapple\n"); -#endif //DEBUG_GRAPPLE - // - ms->grapplevisible_time = AAS_Time(); - // - VectorSubtract(reach->start, ms->origin, dir); - if (!(ms->moveflags & MFL_SWIMMING)) dir[2] = 0; - VectorAdd(ms->origin, ms->viewoffset, org); - VectorSubtract(reach->end, org, viewdir); - // - dist = VectorNormalize(dir); - Vector2Angles(viewdir, result.ideal_viewangles); - result.flags |= MOVERESULT_MOVEMENTVIEW; - // - if (dist < 5 && - fabs(AngleDiff(result.ideal_viewangles[0], ms->viewangles[0])) < 2 && - fabs(AngleDiff(result.ideal_viewangles[1], ms->viewangles[1])) < 2) - { -#ifdef DEBUG_GRAPPLE - botimport.Print(PRT_MESSAGE, "BotTravel_Grapple: activating grapple\n"); -#endif //DEBUG_GRAPPLE - //check if the grapple missile path is clear - VectorAdd(ms->origin, ms->viewoffset, org); - trace = AAS_Trace(org, NULL, NULL, reach->end, ms->entitynum, CONTENTS_SOLID); - VectorSubtract(reach->end, trace.endpos, dir); - if (VectorLength(dir) > 16) - { - result.failure = qtrue; - return result; - } //end if - //activate the grapple - if (offhandgrapple->value) - { - EA_Command(ms->client, cmd_grappleon->string); - } //end if - else - { - EA_Attack(ms->client); - } //end else - ms->moveflags |= MFL_ACTIVEGRAPPLE; - ms->lastgrappledist = 999999; - } //end if - else - { - if (dist < 70) speed = 300 - (300 - 4 * dist); - else speed = 400; - // - BotCheckBlocked(ms, dir, qtrue, &result); - //elemantary action move in direction - EA_Move(ms->client, dir, speed); - VectorCopy(dir, result.movedir); - } //end else - //if in another area before actually grappling - areanum = AAS_PointAreaNum(ms->origin); - if (areanum && areanum != ms->reachareanum) ms->reachability_time = 0; - } //end else - return result; -} //end of the function BotTravel_Grapple -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_moveresult_t BotTravel_RocketJump(bot_movestate_t *ms, aas_reachability_t *reach) -{ - vec3_t hordir; - float dist, speed; - bot_moveresult_t_cleared( result ); - - //botimport.Print(PRT_MESSAGE, "BotTravel_RocketJump: bah\n"); - // - hordir[0] = reach->start[0] - ms->origin[0]; - hordir[1] = reach->start[1] - ms->origin[1]; - hordir[2] = 0; - // - dist = VectorNormalize(hordir); - //look in the movement direction - Vector2Angles(hordir, result.ideal_viewangles); - //look straight down - result.ideal_viewangles[PITCH] = 90; - // - if (dist < 5 && - fabs(AngleDiff(result.ideal_viewangles[0], ms->viewangles[0])) < 5 && - fabs(AngleDiff(result.ideal_viewangles[1], ms->viewangles[1])) < 5) - { - //botimport.Print(PRT_MESSAGE, "between jump start and run start point\n"); - hordir[0] = reach->end[0] - ms->origin[0]; - hordir[1] = reach->end[1] - ms->origin[1]; - hordir[2] = 0; - VectorNormalize(hordir); - //elemantary action jump - EA_Jump(ms->client); - EA_Attack(ms->client); - EA_Move(ms->client, hordir, 800); - // - ms->jumpreach = ms->lastreachnum; - } //end if - else - { - if (dist > 80) dist = 80; - speed = 400 - (400 - 5 * dist); - EA_Move(ms->client, hordir, speed); - } //end else - //look in the movement direction - Vector2Angles(hordir, result.ideal_viewangles); - //look straight down - result.ideal_viewangles[PITCH] = 90; - //set the view angles directly - EA_View(ms->client, result.ideal_viewangles); - //view is important for the movment - result.flags |= MOVERESULT_MOVEMENTVIEWSET; - //select the rocket launcher - EA_SelectWeapon(ms->client, (int) weapindex_rocketlauncher->value); - //weapon is used for movement - result.weapon = (int) weapindex_rocketlauncher->value; - result.flags |= MOVERESULT_MOVEMENTWEAPON; - // - VectorCopy(hordir, result.movedir); - // - return result; -} //end of the function BotTravel_RocketJump -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_moveresult_t BotTravel_BFGJump(bot_movestate_t *ms, aas_reachability_t *reach) -{ - vec3_t hordir; - float dist, speed; - bot_moveresult_t_cleared( result ); - - //botimport.Print(PRT_MESSAGE, "BotTravel_BFGJump: bah\n"); - // - hordir[0] = reach->start[0] - ms->origin[0]; - hordir[1] = reach->start[1] - ms->origin[1]; - hordir[2] = 0; - // - dist = VectorNormalize(hordir); - // - if (dist < 5 && - fabs(AngleDiff(result.ideal_viewangles[0], ms->viewangles[0])) < 5 && - fabs(AngleDiff(result.ideal_viewangles[1], ms->viewangles[1])) < 5) - { - //botimport.Print(PRT_MESSAGE, "between jump start and run start point\n"); - hordir[0] = reach->end[0] - ms->origin[0]; - hordir[1] = reach->end[1] - ms->origin[1]; - hordir[2] = 0; - VectorNormalize(hordir); - //elemantary action jump - EA_Jump(ms->client); - EA_Attack(ms->client); - EA_Move(ms->client, hordir, 800); - // - ms->jumpreach = ms->lastreachnum; - } //end if - else - { - if (dist > 80) dist = 80; - speed = 400 - (400 - 5 * dist); - EA_Move(ms->client, hordir, speed); - } //end else - //look in the movement direction - Vector2Angles(hordir, result.ideal_viewangles); - //look straight down - result.ideal_viewangles[PITCH] = 90; - //set the view angles directly - EA_View(ms->client, result.ideal_viewangles); - //view is important for the movment - result.flags |= MOVERESULT_MOVEMENTVIEWSET; - //select the rocket launcher - EA_SelectWeapon(ms->client, (int) weapindex_bfg10k->value); - //weapon is used for movement - result.weapon = (int) weapindex_bfg10k->value; - result.flags |= MOVERESULT_MOVEMENTWEAPON; - // - VectorCopy(hordir, result.movedir); - // - return result; -} //end of the function BotTravel_BFGJump -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_moveresult_t BotFinishTravel_WeaponJump(bot_movestate_t *ms, aas_reachability_t *reach) -{ - vec3_t hordir; - float speed; - bot_moveresult_t_cleared( result ); - - //if not jumped yet - if (!ms->jumpreach) return result; - /* - //go straight to the reachability end - hordir[0] = reach->end[0] - ms->origin[0]; - hordir[1] = reach->end[1] - ms->origin[1]; - hordir[2] = 0; - VectorNormalize(hordir); - //always use max speed when traveling through the air - EA_Move(ms->client, hordir, 800); - VectorCopy(hordir, result.movedir); - */ - // - if (!BotAirControl(ms->origin, ms->velocity, reach->end, hordir, &speed)) - { - //go straight to the reachability end - VectorSubtract(reach->end, ms->origin, hordir); - hordir[2] = 0; - VectorNormalize(hordir); - speed = 400; - } //end if - // - EA_Move(ms->client, hordir, speed); - VectorCopy(hordir, result.movedir); - // - return result; -} //end of the function BotFinishTravel_WeaponJump -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_moveresult_t BotTravel_JumpPad(bot_movestate_t *ms, aas_reachability_t *reach) -{ - float dist, speed; - vec3_t hordir; - bot_moveresult_t_cleared( result ); - - //first walk straight to the reachability start - hordir[0] = reach->start[0] - ms->origin[0]; - hordir[1] = reach->start[1] - ms->origin[1]; - hordir[2] = 0; - dist = VectorNormalize(hordir); - // - BotCheckBlocked(ms, hordir, qtrue, &result); - speed = 400; - //elemantary action move in direction - EA_Move(ms->client, hordir, speed); - VectorCopy(hordir, result.movedir); - // - return result; -} //end of the function BotTravel_JumpPad -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_moveresult_t BotFinishTravel_JumpPad(bot_movestate_t *ms, aas_reachability_t *reach) -{ - float speed; - vec3_t hordir; - bot_moveresult_t_cleared( result ); - - if (!BotAirControl(ms->origin, ms->velocity, reach->end, hordir, &speed)) - { - hordir[0] = reach->end[0] - ms->origin[0]; - hordir[1] = reach->end[1] - ms->origin[1]; - hordir[2] = 0; - VectorNormalize(hordir); - speed = 400; - } //end if - BotCheckBlocked(ms, hordir, qtrue, &result); - //elemantary action move in direction - EA_Move(ms->client, hordir, speed); - VectorCopy(hordir, result.movedir); - // - return result; -} //end of the function BotFinishTravel_JumpPad -//=========================================================================== -// time before the reachability times out -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotReachabilityTime(aas_reachability_t *reach) -{ - switch(reach->traveltype & TRAVELTYPE_MASK) - { - case TRAVEL_WALK: return 5; - case TRAVEL_CROUCH: return 5; - case TRAVEL_BARRIERJUMP: return 5; - case TRAVEL_LADDER: return 6; - case TRAVEL_WALKOFFLEDGE: return 5; - case TRAVEL_JUMP: return 5; - case TRAVEL_SWIM: return 5; - case TRAVEL_WATERJUMP: return 5; - case TRAVEL_TELEPORT: return 5; - case TRAVEL_ELEVATOR: return 10; - case TRAVEL_GRAPPLEHOOK: return 8; - case TRAVEL_ROCKETJUMP: return 6; - case TRAVEL_BFGJUMP: return 6; - case TRAVEL_JUMPPAD: return 10; - case TRAVEL_FUNCBOB: return 10; - default: - { - botimport.Print(PRT_ERROR, "travel type %d not implemented yet\n", reach->traveltype); - return 8; - } //end case - } //end switch -} //end of the function BotReachabilityTime -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -bot_moveresult_t BotMoveInGoalArea(bot_movestate_t *ms, bot_goal_t *goal) -{ - bot_moveresult_t_cleared( result ); - vec3_t dir; - float dist, speed; - -#ifdef DEBUG - //botimport.Print(PRT_MESSAGE, "%s: moving straight to goal\n", ClientName(ms->entitynum-1)); - //AAS_ClearShownDebugLines(); - //AAS_DebugLine(ms->origin, goal->origin, LINECOLOR_RED); -#endif //DEBUG - //walk straight to the goal origin - dir[0] = goal->origin[0] - ms->origin[0]; - dir[1] = goal->origin[1] - ms->origin[1]; - if (ms->moveflags & MFL_SWIMMING) - { - dir[2] = goal->origin[2] - ms->origin[2]; - result.traveltype = TRAVEL_SWIM; - } //end if - else - { - dir[2] = 0; - result.traveltype = TRAVEL_WALK; - } //endif - // - dist = VectorNormalize(dir); - if (dist > 100) dist = 100; - speed = 400 - (400 - 4 * dist); - if (speed < 10) speed = 0; - // - BotCheckBlocked(ms, dir, qtrue, &result); - //elemantary action move in direction - EA_Move(ms->client, dir, speed); - VectorCopy(dir, result.movedir); - // - if (ms->moveflags & MFL_SWIMMING) - { - Vector2Angles(dir, result.ideal_viewangles); - result.flags |= MOVERESULT_SWIMVIEW; - } //end if - //if (!debugline) debugline = botimport.DebugLineCreate(); - //botimport.DebugLineShow(debugline, ms->origin, goal->origin, LINECOLOR_BLUE); - // - ms->lastreachnum = 0; - ms->lastareanum = 0; - ms->lastgoalareanum = goal->areanum; - VectorCopy(ms->origin, ms->lastorigin); - // - return result; -} //end of the function BotMoveInGoalArea -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotMoveToGoal(bot_moveresult_t *result, int movestate, bot_goal_t *goal, int travelflags) -{ - int reachnum, lastreachnum, foundjumppad, ent, resultflags; - aas_reachability_t reach, lastreach; - bot_movestate_t *ms; - //vec3_t mins, maxs, up = {0, 0, 1}; - //bsp_trace_t trace; - //static int debugline; - - result->failure = qfalse; - result->type = 0; - result->blocked = qfalse; - result->blockentity = 0; - result->traveltype = 0; - result->flags = 0; - - // - ms = BotMoveStateFromHandle(movestate); - if (!ms) return; - //reset the grapple before testing if the bot has a valid goal - //because the bot could loose all it's goals when stuck to a wall - BotResetGrapple(ms); - // - if (!goal) - { -#ifdef DEBUG - botimport.Print(PRT_MESSAGE, "client %d: movetogoal -> no goal\n", ms->client); -#endif //DEBUG - result->failure = qtrue; - return; - } //end if - //botimport.Print(PRT_MESSAGE, "numavoidreach = %d\n", ms->numavoidreach); - //remove some of the move flags - ms->moveflags &= ~(MFL_SWIMMING|MFL_AGAINSTLADDER); - //set some of the move flags - //NOTE: the MFL_ONGROUND flag is also set in the higher AI - if (AAS_OnGround(ms->origin, ms->presencetype, ms->entitynum)) ms->moveflags |= MFL_ONGROUND; - // - if (ms->moveflags & MFL_ONGROUND) - { - int modeltype, modelnum; - - ent = BotOnTopOfEntity(ms); - - if (ent != -1) - { - modelnum = AAS_EntityModelindex(ent); - if (modelnum >= 0 && modelnum < MAX_MODELS) - { - modeltype = modeltypes[modelnum]; - - if (modeltype == MODELTYPE_FUNC_PLAT) - { - AAS_ReachabilityFromNum(ms->lastreachnum, &reach); - //if the bot is Not using the elevator - if ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_ELEVATOR || - //NOTE: the face number is the plat model number - (reach.facenum & 0x0000FFFF) != modelnum) - { - reachnum = AAS_NextModelReachability(0, modelnum); - if (reachnum) - { - //botimport.Print(PRT_MESSAGE, "client %d: accidentally ended up on func_plat\n", ms->client); - AAS_ReachabilityFromNum(reachnum, &reach); - ms->lastreachnum = reachnum; - ms->reachability_time = AAS_Time() + BotReachabilityTime(&reach); - } //end if - else - { - if (bot_developer) - { - botimport.Print(PRT_MESSAGE, "client %d: on func_plat without reachability\n", ms->client); - } //end if - result->blocked = qtrue; - result->blockentity = ent; - result->flags |= MOVERESULT_ONTOPOFOBSTACLE; - return; - } //end else - } //end if - result->flags |= MOVERESULT_ONTOPOF_ELEVATOR; - } //end if - else if (modeltype == MODELTYPE_FUNC_BOB) - { - AAS_ReachabilityFromNum(ms->lastreachnum, &reach); - //if the bot is Not using the func bobbing - if ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_FUNCBOB || - //NOTE: the face number is the func_bobbing model number - (reach.facenum & 0x0000FFFF) != modelnum) - { - reachnum = AAS_NextModelReachability(0, modelnum); - if (reachnum) - { - //botimport.Print(PRT_MESSAGE, "client %d: accidentally ended up on func_bobbing\n", ms->client); - AAS_ReachabilityFromNum(reachnum, &reach); - ms->lastreachnum = reachnum; - ms->reachability_time = AAS_Time() + BotReachabilityTime(&reach); - } //end if - else - { - if (bot_developer) - { - botimport.Print(PRT_MESSAGE, "client %d: on func_bobbing without reachability\n", ms->client); - } //end if - result->blocked = qtrue; - result->blockentity = ent; - result->flags |= MOVERESULT_ONTOPOFOBSTACLE; - return; - } //end else - } //end if - result->flags |= MOVERESULT_ONTOPOF_FUNCBOB; - } //end if - else if (modeltype == MODELTYPE_FUNC_STATIC || modeltype == MODELTYPE_FUNC_DOOR) - { - // check if ontop of a door bridge ? - ms->areanum = BotFuzzyPointReachabilityArea(ms->origin); - // if not in a reachability area - if (!AAS_AreaReachability(ms->areanum)) - { - result->blocked = qtrue; - result->blockentity = ent; - result->flags |= MOVERESULT_ONTOPOFOBSTACLE; - return; - } //end if - } //end else if - else - { - result->blocked = qtrue; - result->blockentity = ent; - result->flags |= MOVERESULT_ONTOPOFOBSTACLE; - return; - } //end else - } //end if - } //end if - } //end if - //if swimming - if (AAS_Swimming(ms->origin)) ms->moveflags |= MFL_SWIMMING; - //if against a ladder - if (AAS_AgainstLadder(ms->origin)) ms->moveflags |= MFL_AGAINSTLADDER; - //if the bot is on the ground, swimming or against a ladder - if (ms->moveflags & (MFL_ONGROUND|MFL_SWIMMING|MFL_AGAINSTLADDER)) - { - //botimport.Print(PRT_MESSAGE, "%s: onground, swimming or against ladder\n", ClientName(ms->entitynum-1)); - // - AAS_ReachabilityFromNum(ms->lastreachnum, &lastreach); - //reachability area the bot is in - //ms->areanum = BotReachabilityArea(ms->origin, ((lastreach.traveltype & TRAVELTYPE_MASK) != TRAVEL_ELEVATOR)); - ms->areanum = BotFuzzyPointReachabilityArea(ms->origin); - // - if ( !ms->areanum ) - { - result->failure = qtrue; - result->blocked = qtrue; - result->blockentity = 0; - result->type = RESULTTYPE_INSOLIDAREA; - return; - } //end if - //if the bot is in the goal area - if (ms->areanum == goal->areanum) - { - *result = BotMoveInGoalArea(ms, goal); - return; - } //end if - //assume we can use the reachability from the last frame - reachnum = ms->lastreachnum; - //if there is a last reachability - if (reachnum) - { - AAS_ReachabilityFromNum(reachnum, &reach); - //check if the reachability is still valid - if (!(AAS_TravelFlagForType(reach.traveltype) & travelflags)) - { - reachnum = 0; - } //end if - //special grapple hook case - else if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_GRAPPLEHOOK) - { - if (ms->reachability_time < AAS_Time() || - (ms->moveflags & MFL_GRAPPLERESET)) - { - reachnum = 0; - } //end if - } //end if - //special elevator case - else if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_ELEVATOR || - (reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_FUNCBOB) - { - if ((result->flags & MOVERESULT_ONTOPOF_FUNCBOB) || - (result->flags & MOVERESULT_ONTOPOF_FUNCBOB)) - { - ms->reachability_time = AAS_Time() + 5; - } //end if - //if the bot was going for an elevator and reached the reachability area - if (ms->areanum == reach.areanum || - ms->reachability_time < AAS_Time()) - { - reachnum = 0; - } //end if - } //end if - else - { -#ifdef DEBUG - if (bot_developer) - { - if (ms->reachability_time < AAS_Time()) - { - botimport.Print(PRT_MESSAGE, "client %d: reachability timeout in ", ms->client); - AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK); - botimport.Print(PRT_MESSAGE, "\n"); - } //end if - /* - if (ms->lastareanum != ms->areanum) - { - botimport.Print(PRT_MESSAGE, "changed from area %d to %d\n", ms->lastareanum, ms->areanum); - } //end if*/ - } //end if -#endif //DEBUG - //if the goal area changed or the reachability timed out - //or the area changed - if (ms->lastgoalareanum != goal->areanum || - ms->reachability_time < AAS_Time() || - ms->lastareanum != ms->areanum) - { - reachnum = 0; - //botimport.Print(PRT_MESSAGE, "area change or timeout\n"); - } //end else if - } //end else - } //end if - resultflags = 0; - //if the bot needs a new reachability - if (!reachnum) - { - //if the area has no reachability links - if (!AAS_AreaReachability(ms->areanum)) - { -#ifdef DEBUG - if (bot_developer) - { - botimport.Print(PRT_MESSAGE, "area %d no reachability\n", ms->areanum); - } //end if -#endif //DEBUG - } //end if - //get a new reachability leading towards the goal - reachnum = BotGetReachabilityToGoal(ms->origin, ms->areanum, - ms->lastgoalareanum, ms->lastareanum, - ms->avoidreach, ms->avoidreachtimes, ms->avoidreachtries, - goal, travelflags, travelflags, - ms->avoidspots, ms->numavoidspots, &resultflags); - //the area number the reachability starts in - ms->reachareanum = ms->areanum; - //reset some state variables - ms->jumpreach = 0; //for TRAVEL_JUMP - ms->moveflags &= ~MFL_GRAPPLERESET; //for TRAVEL_GRAPPLEHOOK - //if there is a reachability to the goal - if (reachnum) - { - AAS_ReachabilityFromNum(reachnum, &reach); - //set a timeout for this reachability - ms->reachability_time = AAS_Time() + BotReachabilityTime(&reach); - // -#ifdef AVOIDREACH - //add the reachability to the reachabilities to avoid for a while - BotAddToAvoidReach(ms, reachnum, AVOIDREACH_TIME); -#endif //AVOIDREACH - } //end if -#ifdef DEBUG - - else if (bot_developer) - { - botimport.Print(PRT_MESSAGE, "goal not reachable\n"); - Com_Memset(&reach, 0, sizeof(aas_reachability_t)); //make compiler happy - } //end else - if (bot_developer) - { - //if still going for the same goal - if (ms->lastgoalareanum == goal->areanum) - { - if (ms->lastareanum == reach.areanum) - { - botimport.Print(PRT_MESSAGE, "same goal, going back to previous area\n"); - } //end if - } //end if - } //end if -#endif //DEBUG - } //end else - // - ms->lastreachnum = reachnum; - ms->lastgoalareanum = goal->areanum; - ms->lastareanum = ms->areanum; - //if the bot has a reachability - if (reachnum) - { - //get the reachability from the number - AAS_ReachabilityFromNum(reachnum, &reach); - result->traveltype = reach.traveltype; - // -#ifdef DEBUG_AI_MOVE - AAS_ClearShownDebugLines(); - AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK); - AAS_ShowReachability(&reach); -#endif //DEBUG_AI_MOVE - // -#ifdef DEBUG - //botimport.Print(PRT_MESSAGE, "client %d: ", ms->client); - //AAS_PrintTravelType(reach.traveltype); - //botimport.Print(PRT_MESSAGE, "\n"); -#endif //DEBUG - switch(reach.traveltype & TRAVELTYPE_MASK) - { - case TRAVEL_WALK: *result = BotTravel_Walk(ms, &reach); break; - case TRAVEL_CROUCH: *result = BotTravel_Crouch(ms, &reach); break; - case TRAVEL_BARRIERJUMP: *result = BotTravel_BarrierJump(ms, &reach); break; - case TRAVEL_LADDER: *result = BotTravel_Ladder(ms, &reach); break; - case TRAVEL_WALKOFFLEDGE: *result = BotTravel_WalkOffLedge(ms, &reach); break; - case TRAVEL_JUMP: *result = BotTravel_Jump(ms, &reach); break; - case TRAVEL_SWIM: *result = BotTravel_Swim(ms, &reach); break; - case TRAVEL_WATERJUMP: *result = BotTravel_WaterJump(ms, &reach); break; - case TRAVEL_TELEPORT: *result = BotTravel_Teleport(ms, &reach); break; - case TRAVEL_ELEVATOR: *result = BotTravel_Elevator(ms, &reach); break; - case TRAVEL_GRAPPLEHOOK: *result = BotTravel_Grapple(ms, &reach); break; - case TRAVEL_ROCKETJUMP: *result = BotTravel_RocketJump(ms, &reach); break; - case TRAVEL_BFGJUMP: *result = BotTravel_BFGJump(ms, &reach); break; - case TRAVEL_JUMPPAD: *result = BotTravel_JumpPad(ms, &reach); break; - case TRAVEL_FUNCBOB: *result = BotTravel_FuncBobbing(ms, &reach); break; - default: - { - botimport.Print(PRT_FATAL, "travel type %d not implemented yet\n", (reach.traveltype & TRAVELTYPE_MASK)); - break; - } //end case - } //end switch - result->traveltype = reach.traveltype; - result->flags |= resultflags; - } //end if - else - { - result->failure = qtrue; - result->flags |= resultflags; - Com_Memset(&reach, 0, sizeof(aas_reachability_t)); - } //end else -#ifdef DEBUG - if (bot_developer) - { - if (result->failure) - { - botimport.Print(PRT_MESSAGE, "client %d: movement failure in ", ms->client); - AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK); - botimport.Print(PRT_MESSAGE, "\n"); - } //end if - } //end if -#endif //DEBUG - } //end if - else - { - int i, numareas, areas[16]; - vec3_t end; - - //special handling of jump pads when the bot uses a jump pad without knowing it - foundjumppad = qfalse; - VectorMA(ms->origin, -2 * ms->thinktime, ms->velocity, end); - numareas = AAS_TraceAreas(ms->origin, end, areas, NULL, 16); - for (i = numareas-1; i >= 0; i--) - { - if (AAS_AreaJumpPad(areas[i])) - { - //botimport.Print(PRT_MESSAGE, "client %d used a jumppad without knowing, area %d\n", ms->client, areas[i]); - foundjumppad = qtrue; - lastreachnum = BotGetReachabilityToGoal(end, areas[i], - ms->lastgoalareanum, ms->lastareanum, - ms->avoidreach, ms->avoidreachtimes, ms->avoidreachtries, - goal, travelflags, TFL_JUMPPAD, ms->avoidspots, ms->numavoidspots, NULL); - if (lastreachnum) - { - ms->lastreachnum = lastreachnum; - ms->lastareanum = areas[i]; - //botimport.Print(PRT_MESSAGE, "found jumppad reachability\n"); - break; - } //end if - else - { - for (lastreachnum = AAS_NextAreaReachability(areas[i], 0); lastreachnum; - lastreachnum = AAS_NextAreaReachability(areas[i], lastreachnum)) - { - //get the reachability from the number - AAS_ReachabilityFromNum(lastreachnum, &reach); - if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMPPAD) - { - ms->lastreachnum = lastreachnum; - ms->lastareanum = areas[i]; - //botimport.Print(PRT_MESSAGE, "found jumppad reachability hard!!\n"); - break; - } //end if - } //end for - if (lastreachnum) break; - } //end else - } //end if - } //end for - if (bot_developer) - { - //if a jumppad is found with the trace but no reachability is found - if (foundjumppad && !ms->lastreachnum) - { - botimport.Print(PRT_MESSAGE, "client %d didn't find jumppad reachability\n", ms->client); - } //end if - } //end if - // - if (ms->lastreachnum) - { - //botimport.Print(PRT_MESSAGE, "%s: NOT onground, swimming or against ladder\n", ClientName(ms->entitynum-1)); - AAS_ReachabilityFromNum(ms->lastreachnum, &reach); - result->traveltype = reach.traveltype; -#ifdef DEBUG - //botimport.Print(PRT_MESSAGE, "client %d finish: ", ms->client); - //AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK); - //botimport.Print(PRT_MESSAGE, "\n"); -#endif //DEBUG - // - switch(reach.traveltype & TRAVELTYPE_MASK) - { - case TRAVEL_WALK: *result = BotTravel_Walk(ms, &reach); break;//BotFinishTravel_Walk(ms, &reach); break; - case TRAVEL_CROUCH: /*do nothing*/ break; - case TRAVEL_BARRIERJUMP: *result = BotFinishTravel_BarrierJump(ms, &reach); break; - case TRAVEL_LADDER: *result = BotTravel_Ladder(ms, &reach); break; - case TRAVEL_WALKOFFLEDGE: *result = BotFinishTravel_WalkOffLedge(ms, &reach); break; - case TRAVEL_JUMP: *result = BotFinishTravel_Jump(ms, &reach); break; - case TRAVEL_SWIM: *result = BotTravel_Swim(ms, &reach); break; - case TRAVEL_WATERJUMP: *result = BotFinishTravel_WaterJump(ms, &reach); break; - case TRAVEL_TELEPORT: /*do nothing*/ break; - case TRAVEL_ELEVATOR: *result = BotFinishTravel_Elevator(ms, &reach); break; - case TRAVEL_GRAPPLEHOOK: *result = BotTravel_Grapple(ms, &reach); break; - case TRAVEL_ROCKETJUMP: - case TRAVEL_BFGJUMP: *result = BotFinishTravel_WeaponJump(ms, &reach); break; - case TRAVEL_JUMPPAD: *result = BotFinishTravel_JumpPad(ms, &reach); break; - case TRAVEL_FUNCBOB: *result = BotFinishTravel_FuncBobbing(ms, &reach); break; - default: - { - botimport.Print(PRT_FATAL, "(last) travel type %d not implemented yet\n", (reach.traveltype & TRAVELTYPE_MASK)); - break; - } //end case - } //end switch - result->traveltype = reach.traveltype; -#ifdef DEBUG - if (bot_developer) - { - if (result->failure) - { - botimport.Print(PRT_MESSAGE, "client %d: movement failure in finish ", ms->client); - AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK); - botimport.Print(PRT_MESSAGE, "\n"); - } //end if - } //end if -#endif //DEBUG - } //end if - } //end else - //FIXME: is it right to do this here? - if (result->blocked) ms->reachability_time -= 10 * ms->thinktime; - //copy the last origin - VectorCopy(ms->origin, ms->lastorigin); - //return the movement result - return; -} //end of the function BotMoveToGoal -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotResetAvoidReach(int movestate) -{ - bot_movestate_t *ms; - - ms = BotMoveStateFromHandle(movestate); - if (!ms) return; - Com_Memset(ms->avoidreach, 0, MAX_AVOIDREACH * sizeof(int)); - Com_Memset(ms->avoidreachtimes, 0, MAX_AVOIDREACH * sizeof(float)); - Com_Memset(ms->avoidreachtries, 0, MAX_AVOIDREACH * sizeof(int)); -} //end of the function BotResetAvoidReach -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotResetLastAvoidReach(int movestate) -{ - int i, latest; - float latesttime; - bot_movestate_t *ms; - - ms = BotMoveStateFromHandle(movestate); - if (!ms) return; - latesttime = 0; - latest = 0; - for (i = 0; i < MAX_AVOIDREACH; i++) - { - if (ms->avoidreachtimes[i] > latesttime) - { - latesttime = ms->avoidreachtimes[i]; - latest = i; - } //end if - } //end for - if (latesttime) - { - ms->avoidreachtimes[latest] = 0; - if (ms->avoidreachtries[i] > 0) ms->avoidreachtries[latest]--; - } //end if -} //end of the function BotResetLastAvoidReach -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotResetMoveState(int movestate) -{ - bot_movestate_t *ms; - - ms = BotMoveStateFromHandle(movestate); - if (!ms) return; - Com_Memset(ms, 0, sizeof(bot_movestate_t)); -} //end of the function BotResetMoveState -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotSetupMoveAI(void) -{ - BotSetBrushModelTypes(); - sv_maxstep = LibVar("sv_step", "18"); - sv_maxbarrier = LibVar("sv_maxbarrier", "32"); - sv_gravity = LibVar("sv_gravity", "800"); - weapindex_rocketlauncher = LibVar("weapindex_rocketlauncher", "5"); - weapindex_bfg10k = LibVar("weapindex_bfg10k", "9"); - weapindex_grapple = LibVar("weapindex_grapple", "10"); - entitytypemissile = LibVar("entitytypemissile", "3"); - offhandgrapple = LibVar("offhandgrapple", "0"); - cmd_grappleon = LibVar("cmd_grappleon", "grappleon"); - cmd_grappleoff = LibVar("cmd_grappleoff", "grappleoff"); - return BLERR_NOERROR; -} //end of the function BotSetupMoveAI -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotShutdownMoveAI(void) -{ - int i; - - for (i = 1; i <= MAX_CLIENTS; i++) - { - if (botmovestates[i]) - { - FreeMemory(botmovestates[i]); - botmovestates[i] = NULL; - } //end if - } //end for -} //end of the function BotShutdownMoveAI - - diff --git a/src/botlib/be_ai_move.h b/src/botlib/be_ai_move.h deleted file mode 100644 index 8b1ba0dd..00000000 --- a/src/botlib/be_ai_move.h +++ /dev/null @@ -1,145 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// - -/***************************************************************************** - * name: be_ai_move.h - * - * desc: movement AI - * - * $Archive: /source/code/botlib/be_ai_move.h $ - * - *****************************************************************************/ - -//movement types -#define MOVE_WALK 1 -#define MOVE_CROUCH 2 -#define MOVE_JUMP 4 -#define MOVE_GRAPPLE 8 -#define MOVE_ROCKETJUMP 16 -#define MOVE_BFGJUMP 32 -//move flags -#define MFL_BARRIERJUMP 1 //bot is performing a barrier jump -#define MFL_ONGROUND 2 //bot is in the ground -#define MFL_SWIMMING 4 //bot is swimming -#define MFL_AGAINSTLADDER 8 //bot is against a ladder -#define MFL_WATERJUMP 16 //bot is waterjumping -#define MFL_TELEPORTED 32 //bot is being teleported -#define MFL_GRAPPLEPULL 64 //bot is being pulled by the grapple -#define MFL_ACTIVEGRAPPLE 128 //bot is using the grapple hook -#define MFL_GRAPPLERESET 256 //bot has reset the grapple -#define MFL_WALK 512 //bot should walk slowly -// move result flags -#define MOVERESULT_MOVEMENTVIEW 1 //bot uses view for movement -#define MOVERESULT_SWIMVIEW 2 //bot uses view for swimming -#define MOVERESULT_WAITING 4 //bot is waiting for something -#define MOVERESULT_MOVEMENTVIEWSET 8 //bot has set the view in movement code -#define MOVERESULT_MOVEMENTWEAPON 16 //bot uses weapon for movement -#define MOVERESULT_ONTOPOFOBSTACLE 32 //bot is ontop of obstacle -#define MOVERESULT_ONTOPOF_FUNCBOB 64 //bot is ontop of a func_bobbing -#define MOVERESULT_ONTOPOF_ELEVATOR 128 //bot is ontop of an elevator (func_plat) -#define MOVERESULT_BLOCKEDBYAVOIDSPOT 256 //bot is blocked by an avoid spot -// -#define MAX_AVOIDREACH 1 -#define MAX_AVOIDSPOTS 32 -// avoid spot types -#define AVOID_CLEAR 0 //clear all avoid spots -#define AVOID_ALWAYS 1 //avoid always -#define AVOID_DONTBLOCK 2 //never totally block -// restult types -#define RESULTTYPE_ELEVATORUP 1 //elevator is up -#define RESULTTYPE_WAITFORFUNCBOBBING 2 //waiting for func bobbing to arrive -#define RESULTTYPE_BADGRAPPLEPATH 4 //grapple path is obstructed -#define RESULTTYPE_INSOLIDAREA 8 //stuck in solid area, this is bad - -//structure used to initialize the movement state -//the or_moveflags MFL_ONGROUND, MFL_TELEPORTED and MFL_WATERJUMP come from the playerstate -typedef struct bot_initmove_s -{ - vec3_t origin; //origin of the bot - vec3_t velocity; //velocity of the bot - vec3_t viewoffset; //view offset - int entitynum; //entity number of the bot - int client; //client number of the bot - float thinktime; //time the bot thinks - int presencetype; //presencetype of the bot - vec3_t viewangles; //view angles of the bot - int or_moveflags; //values ored to the movement flags -} bot_initmove_t; - -//NOTE: the ideal_viewangles are only valid if MFL_MOVEMENTVIEW is set -typedef struct bot_moveresult_s -{ - int failure; //true if movement failed all together - int type; //failure or blocked type - int blocked; //true if blocked by an entity - int blockentity; //entity blocking the bot - int traveltype; //last executed travel type - int flags; //result flags - int weapon; //weapon used for movement - vec3_t movedir; //movement direction - vec3_t ideal_viewangles; //ideal viewangles for the movement -} bot_moveresult_t; - -#define bot_moveresult_t_cleared(x) bot_moveresult_t (x) = {0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, {0, 0, 0}} - -// bk001204: from code/botlib/be_ai_move.c -// TTimo 04/12/2001 was moved here to avoid dup defines -typedef struct bot_avoidspot_s -{ - vec3_t origin; - float radius; - int type; -} bot_avoidspot_t; - -//resets the whole move state -void BotResetMoveState(int movestate); -//moves the bot to the given goal -void BotMoveToGoal(bot_moveresult_t *result, int movestate, bot_goal_t *goal, int travelflags); -//moves the bot in the specified direction using the specified type of movement -int BotMoveInDirection(int movestate, vec3_t dir, float speed, int type); -//reset avoid reachability -void BotResetAvoidReach(int movestate); -//resets the last avoid reachability -void BotResetLastAvoidReach(int movestate); -//returns a reachability area if the origin is in one -int BotReachabilityArea(vec3_t origin, int client); -//view target based on movement -int BotMovementViewTarget(int movestate, bot_goal_t *goal, int travelflags, float lookahead, vec3_t target); -//predict the position of a player based on movement towards a goal -int BotPredictVisiblePosition(vec3_t origin, int areanum, bot_goal_t *goal, int travelflags, vec3_t target); -//returns the handle of a newly allocated movestate -int BotAllocMoveState(void); -//frees the movestate with the given handle -void BotFreeMoveState(int handle); -//initialize movement state before performing any movement -void BotInitMoveState(int handle, bot_initmove_t *initmove); -//add a spot to avoid (if type == AVOID_CLEAR all spots are removed) -void BotAddAvoidSpot(int movestate, vec3_t origin, float radius, int type); -//must be called every map change -void BotSetBrushModelTypes(void); -//setup movement AI -int BotSetupMoveAI(void); -//shutdown movement AI -void BotShutdownMoveAI(void); - diff --git a/src/botlib/be_ai_weap.c b/src/botlib/be_ai_weap.c deleted file mode 100644 index 309242ef..00000000 --- a/src/botlib/be_ai_weap.c +++ /dev/null @@ -1,544 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_ai_weap.c - * - * desc: weapon AI - * - * $Archive: /MissionPack/code/botlib/be_ai_weap.c $ - * - *****************************************************************************/ - -#include "../qcommon/q_shared.h" -#include "l_libvar.h" -#include "l_log.h" -#include "l_memory.h" -#include "l_utils.h" -#include "l_script.h" -#include "l_precomp.h" -#include "l_struct.h" -#include "aasfile.h" -#include "botlib.h" -#include "be_aas.h" -#include "be_aas_funcs.h" -#include "be_interface.h" -#include "be_ai_weight.h" //fuzzy weights -#include "be_ai_weap.h" - -//#define DEBUG_AI_WEAP - -//structure field offsets -#define WEAPON_OFS(x) (int)&(((weaponinfo_t *)0)->x) -#define PROJECTILE_OFS(x) (int)&(((projectileinfo_t *)0)->x) - -//weapon definition // bk001212 - static -static fielddef_t weaponinfo_fields[] = -{ -{"number", WEAPON_OFS(number), FT_INT}, //weapon number -{"name", WEAPON_OFS(name), FT_STRING}, //name of the weapon -{"level", WEAPON_OFS(level), FT_INT}, -{"model", WEAPON_OFS(model), FT_STRING}, //model of the weapon -{"weaponindex", WEAPON_OFS(weaponindex), FT_INT}, //index of weapon in inventory -{"flags", WEAPON_OFS(flags), FT_INT}, //special flags -{"projectile", WEAPON_OFS(projectile), FT_STRING}, //projectile used by the weapon -{"numprojectiles", WEAPON_OFS(numprojectiles), FT_INT}, //number of projectiles -{"hspread", WEAPON_OFS(hspread), FT_FLOAT}, //horizontal spread of projectiles (degrees from middle) -{"vspread", WEAPON_OFS(vspread), FT_FLOAT}, //vertical spread of projectiles (degrees from middle) -{"speed", WEAPON_OFS(speed), FT_FLOAT}, //speed of the projectile (0 = instant hit) -{"acceleration", WEAPON_OFS(acceleration), FT_FLOAT}, //"acceleration" * time (in seconds) + "speed" = projectile speed -{"recoil", WEAPON_OFS(recoil), FT_FLOAT|FT_ARRAY, 3}, //amount of recoil the player gets from the weapon -{"offset", WEAPON_OFS(offset), FT_FLOAT|FT_ARRAY, 3}, //projectile start offset relative to eye and view angles -{"angleoffset", WEAPON_OFS(angleoffset), FT_FLOAT|FT_ARRAY, 3},//offset of the shoot angles relative to the view angles -{"extrazvelocity", WEAPON_OFS(extrazvelocity), FT_FLOAT},//extra z velocity the projectile gets -{"ammoamount", WEAPON_OFS(ammoamount), FT_INT}, //ammo amount used per shot -{"ammoindex", WEAPON_OFS(ammoindex), FT_INT}, //index of ammo in inventory -{"activate", WEAPON_OFS(activate), FT_FLOAT}, //time it takes to select the weapon -{"reload", WEAPON_OFS(reload), FT_FLOAT}, //time it takes to reload the weapon -{"spinup", WEAPON_OFS(spinup), FT_FLOAT}, //time it takes before first shot -{"spindown", WEAPON_OFS(spindown), FT_FLOAT}, //time it takes before weapon stops firing -{NULL, 0, 0, 0} -}; - -//projectile definition -static fielddef_t projectileinfo_fields[] = -{ -{"name", PROJECTILE_OFS(name), FT_STRING}, //name of the projectile -{"model", WEAPON_OFS(model), FT_STRING}, //model of the projectile -{"flags", PROJECTILE_OFS(flags), FT_INT}, //special flags -{"gravity", PROJECTILE_OFS(gravity), FT_FLOAT}, //amount of gravity applied to the projectile [0,1] -{"damage", PROJECTILE_OFS(damage), FT_INT}, //damage of the projectile -{"radius", PROJECTILE_OFS(radius), FT_FLOAT}, //radius of damage -{"visdamage", PROJECTILE_OFS(visdamage), FT_INT}, //damage of the projectile to visible entities -{"damagetype", PROJECTILE_OFS(damagetype), FT_INT}, //type of damage (combination of the DAMAGETYPE_? flags) -{"healthinc", PROJECTILE_OFS(healthinc), FT_INT}, //health increase the owner gets -{"push", PROJECTILE_OFS(push), FT_FLOAT}, //amount a player is pushed away from the projectile impact -{"detonation", PROJECTILE_OFS(detonation), FT_FLOAT}, //time before projectile explodes after fire pressed -{"bounce", PROJECTILE_OFS(bounce), FT_FLOAT}, //amount the projectile bounces -{"bouncefric", PROJECTILE_OFS(bouncefric), FT_FLOAT}, //amount the bounce decreases per bounce -{"bouncestop", PROJECTILE_OFS(bouncestop), FT_FLOAT}, //minimum bounce value before bouncing stops -//recurive projectile definition?? -{NULL, 0, 0, 0} -}; - -static structdef_t weaponinfo_struct = -{ - sizeof(weaponinfo_t), weaponinfo_fields -}; -static structdef_t projectileinfo_struct = -{ - sizeof(projectileinfo_t), projectileinfo_fields -}; - -//weapon configuration: set of weapons with projectiles -typedef struct weaponconfig_s -{ - int numweapons; - int numprojectiles; - projectileinfo_t *projectileinfo; - weaponinfo_t *weaponinfo; -} weaponconfig_t; - -//the bot weapon state -typedef struct bot_weaponstate_s -{ - struct weightconfig_s *weaponweightconfig; //weapon weight configuration - int *weaponweightindex; //weapon weight index -} bot_weaponstate_t; - -static bot_weaponstate_t *botweaponstates[MAX_CLIENTS+1]; -static weaponconfig_t *weaponconfig; - -//======================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//======================================================================== -int BotValidWeaponNumber(int weaponnum) -{ - if (weaponnum <= 0 || weaponnum > weaponconfig->numweapons) - { - botimport.Print(PRT_ERROR, "weapon number out of range\n"); - return qfalse; - } //end if - return qtrue; -} //end of the function BotValidWeaponNumber -//======================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//======================================================================== -bot_weaponstate_t *BotWeaponStateFromHandle(int handle) -{ - if (handle <= 0 || handle > MAX_CLIENTS) - { - botimport.Print(PRT_FATAL, "move state handle %d out of range\n", handle); - return NULL; - } //end if - if (!botweaponstates[handle]) - { - botimport.Print(PRT_FATAL, "invalid move state %d\n", handle); - return NULL; - } //end if - return botweaponstates[handle]; -} //end of the function BotWeaponStateFromHandle -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -#ifdef DEBUG_AI_WEAP -void DumpWeaponConfig(weaponconfig_t *wc) -{ - FILE *fp; - int i; - - fp = Log_FileStruct(); - if (!fp) return; - for (i = 0; i < wc->numprojectiles; i++) - { - WriteStructure(fp, &projectileinfo_struct, (char *) &wc->projectileinfo[i]); - Log_Flush(); - } //end for - for (i = 0; i < wc->numweapons; i++) - { - WriteStructure(fp, &weaponinfo_struct, (char *) &wc->weaponinfo[i]); - Log_Flush(); - } //end for -} //end of the function DumpWeaponConfig -#endif //DEBUG_AI_WEAP -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -weaponconfig_t *LoadWeaponConfig(char *filename) -{ - int max_weaponinfo, max_projectileinfo; - token_t token; - char path[MAX_PATH]; - int i, j; - source_t *source; - weaponconfig_t *wc; - weaponinfo_t weaponinfo; - - max_weaponinfo = (int) LibVarValue("max_weaponinfo", "32"); - if (max_weaponinfo < 0) - { - botimport.Print(PRT_ERROR, "max_weaponinfo = %d\n", max_weaponinfo); - max_weaponinfo = 32; - LibVarSet("max_weaponinfo", "32"); - } //end if - max_projectileinfo = (int) LibVarValue("max_projectileinfo", "32"); - if (max_projectileinfo < 0) - { - botimport.Print(PRT_ERROR, "max_projectileinfo = %d\n", max_projectileinfo); - max_projectileinfo = 32; - LibVarSet("max_projectileinfo", "32"); - } //end if - strncpy(path, filename, MAX_PATH); - PC_SetBaseFolder(BOTFILESBASEFOLDER); - source = LoadSourceFile(path); - if (!source) - { - botimport.Print(PRT_ERROR, "counldn't load %s\n", path); - return NULL; - } //end if - //initialize weapon config - wc = (weaponconfig_t *) GetClearedHunkMemory(sizeof(weaponconfig_t) + - max_weaponinfo * sizeof(weaponinfo_t) + - max_projectileinfo * sizeof(projectileinfo_t)); - wc->weaponinfo = (weaponinfo_t *) ((char *) wc + sizeof(weaponconfig_t)); - wc->projectileinfo = (projectileinfo_t *) ((char *) wc->weaponinfo + - max_weaponinfo * sizeof(weaponinfo_t)); - wc->numweapons = max_weaponinfo; - wc->numprojectiles = 0; - //parse the source file - while(PC_ReadToken(source, &token)) - { - if (!strcmp(token.string, "weaponinfo")) - { - Com_Memset(&weaponinfo, 0, sizeof(weaponinfo_t)); - if (!ReadStructure(source, &weaponinfo_struct, (char *) &weaponinfo)) - { - FreeMemory(wc); - FreeSource(source); - return NULL; - } //end if - if (weaponinfo.number < 0 || weaponinfo.number >= max_weaponinfo) - { - botimport.Print(PRT_ERROR, "weapon info number %d out of range in %s\n", weaponinfo.number, path); - FreeMemory(wc); - FreeSource(source); - return NULL; - } //end if - Com_Memcpy(&wc->weaponinfo[weaponinfo.number], &weaponinfo, sizeof(weaponinfo_t)); - wc->weaponinfo[weaponinfo.number].valid = qtrue; - } //end if - else if (!strcmp(token.string, "projectileinfo")) - { - if (wc->numprojectiles >= max_projectileinfo) - { - botimport.Print(PRT_ERROR, "more than %d projectiles defined in %s\n", max_projectileinfo, path); - FreeMemory(wc); - FreeSource(source); - return NULL; - } //end if - Com_Memset(&wc->projectileinfo[wc->numprojectiles], 0, sizeof(projectileinfo_t)); - if (!ReadStructure(source, &projectileinfo_struct, (char *) &wc->projectileinfo[wc->numprojectiles])) - { - FreeMemory(wc); - FreeSource(source); - return NULL; - } //end if - wc->numprojectiles++; - } //end if - else - { - botimport.Print(PRT_ERROR, "unknown definition %s in %s\n", token.string, path); - FreeMemory(wc); - FreeSource(source); - return NULL; - } //end else - } //end while - FreeSource(source); - //fix up weapons - for (i = 0; i < wc->numweapons; i++) - { - if (!wc->weaponinfo[i].valid) continue; - if (!wc->weaponinfo[i].name[0]) - { - botimport.Print(PRT_ERROR, "weapon %d has no name in %s\n", i, path); - FreeMemory(wc); - return NULL; - } //end if - if (!wc->weaponinfo[i].projectile[0]) - { - botimport.Print(PRT_ERROR, "weapon %s has no projectile in %s\n", wc->weaponinfo[i].name, path); - FreeMemory(wc); - return NULL; - } //end if - //find the projectile info and copy it to the weapon info - for (j = 0; j < wc->numprojectiles; j++) - { - if (!strcmp(wc->projectileinfo[j].name, wc->weaponinfo[i].projectile)) - { - Com_Memcpy(&wc->weaponinfo[i].proj, &wc->projectileinfo[j], sizeof(projectileinfo_t)); - break; - } //end if - } //end for - if (j == wc->numprojectiles) - { - botimport.Print(PRT_ERROR, "weapon %s uses undefined projectile in %s\n", wc->weaponinfo[i].name, path); - FreeMemory(wc); - return NULL; - } //end if - } //end for - if (!wc->numweapons) botimport.Print(PRT_WARNING, "no weapon info loaded\n"); - botimport.Print(PRT_MESSAGE, "loaded %s\n", path); - return wc; -} //end of the function LoadWeaponConfig -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int *WeaponWeightIndex(weightconfig_t *wwc, weaponconfig_t *wc) -{ - int *index, i; - - //initialize item weight index - index = (int *) GetClearedMemory(sizeof(int) * wc->numweapons); - - for (i = 0; i < wc->numweapons; i++) - { - index[i] = FindFuzzyWeight(wwc, wc->weaponinfo[i].name); - } //end for - return index; -} //end of the function WeaponWeightIndex -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotFreeWeaponWeights(int weaponstate) -{ - bot_weaponstate_t *ws; - - ws = BotWeaponStateFromHandle(weaponstate); - if (!ws) return; - if (ws->weaponweightconfig) FreeWeightConfig(ws->weaponweightconfig); - if (ws->weaponweightindex) FreeMemory(ws->weaponweightindex); -} //end of the function BotFreeWeaponWeights -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotLoadWeaponWeights(int weaponstate, char *filename) -{ - bot_weaponstate_t *ws; - - ws = BotWeaponStateFromHandle(weaponstate); - if (!ws) return BLERR_CANNOTLOADWEAPONWEIGHTS; - BotFreeWeaponWeights(weaponstate); - // - ws->weaponweightconfig = ReadWeightConfig(filename); - if (!ws->weaponweightconfig) - { - botimport.Print(PRT_FATAL, "couldn't load weapon config %s\n", filename); - return BLERR_CANNOTLOADWEAPONWEIGHTS; - } //end if - if (!weaponconfig) return BLERR_CANNOTLOADWEAPONCONFIG; - ws->weaponweightindex = WeaponWeightIndex(ws->weaponweightconfig, weaponconfig); - return BLERR_NOERROR; -} //end of the function BotLoadWeaponWeights -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotGetWeaponInfo(int weaponstate, int weapon, weaponinfo_t *weaponinfo) -{ - bot_weaponstate_t *ws; - - if (!BotValidWeaponNumber(weapon)) return; - ws = BotWeaponStateFromHandle(weaponstate); - if (!ws) return; - if (!weaponconfig) return; - Com_Memcpy(weaponinfo, &weaponconfig->weaponinfo[weapon], sizeof(weaponinfo_t)); -} //end of the function BotGetWeaponInfo -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotChooseBestFightWeapon(int weaponstate, int *inventory) -{ - int i, index, bestweapon; - float weight, bestweight; - weaponconfig_t *wc; - bot_weaponstate_t *ws; - - ws = BotWeaponStateFromHandle(weaponstate); - if (!ws) return 0; - wc = weaponconfig; - if (!weaponconfig) return 0; - - //if the bot has no weapon weight configuration - if (!ws->weaponweightconfig) return 0; - - bestweight = 0; - bestweapon = 0; - for (i = 0; i < wc->numweapons; i++) - { - if (!wc->weaponinfo[i].valid) continue; - index = ws->weaponweightindex[i]; - if (index < 0) continue; - weight = FuzzyWeight(inventory, ws->weaponweightconfig, index); - if (weight > bestweight) - { - bestweight = weight; - bestweapon = i; - } //end if - } //end for - return bestweapon; -} //end of the function BotChooseBestFightWeapon -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotResetWeaponState(int weaponstate) -{ - struct weightconfig_s *weaponweightconfig; - int *weaponweightindex; - bot_weaponstate_t *ws; - - ws = BotWeaponStateFromHandle(weaponstate); - if (!ws) return; - weaponweightconfig = ws->weaponweightconfig; - weaponweightindex = ws->weaponweightindex; - - //Com_Memset(ws, 0, sizeof(bot_weaponstate_t)); - ws->weaponweightconfig = weaponweightconfig; - ws->weaponweightindex = weaponweightindex; -} //end of the function BotResetWeaponState -//======================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//======================================================================== -int BotAllocWeaponState(void) -{ - int i; - - for (i = 1; i <= MAX_CLIENTS; i++) - { - if (!botweaponstates[i]) - { - botweaponstates[i] = GetClearedMemory(sizeof(bot_weaponstate_t)); - return i; - } //end if - } //end for - return 0; -} //end of the function BotAllocWeaponState -//======================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//======================================================================== -void BotFreeWeaponState(int handle) -{ - if (handle <= 0 || handle > MAX_CLIENTS) - { - botimport.Print(PRT_FATAL, "move state handle %d out of range\n", handle); - return; - } //end if - if (!botweaponstates[handle]) - { - botimport.Print(PRT_FATAL, "invalid move state %d\n", handle); - return; - } //end if - BotFreeWeaponWeights(handle); - FreeMemory(botweaponstates[handle]); - botweaponstates[handle] = NULL; -} //end of the function BotFreeWeaponState -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BotSetupWeaponAI(void) -{ - char *file; - - file = LibVarString("weaponconfig", "weapons.c"); - weaponconfig = LoadWeaponConfig(file); - if (!weaponconfig) - { - botimport.Print(PRT_FATAL, "couldn't load the weapon config\n"); - return BLERR_CANNOTLOADWEAPONCONFIG; - } //end if - -#ifdef DEBUG_AI_WEAP - DumpWeaponConfig(weaponconfig); -#endif //DEBUG_AI_WEAP - // - return BLERR_NOERROR; -} //end of the function BotSetupWeaponAI -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotShutdownWeaponAI(void) -{ - int i; - - if (weaponconfig) FreeMemory(weaponconfig); - weaponconfig = NULL; - - for (i = 1; i <= MAX_CLIENTS; i++) - { - if (botweaponstates[i]) - { - BotFreeWeaponState(i); - } //end if - } //end for -} //end of the function BotShutdownWeaponAI - diff --git a/src/botlib/be_ai_weap.h b/src/botlib/be_ai_weap.h deleted file mode 100644 index 2b5678e9..00000000 --- a/src/botlib/be_ai_weap.h +++ /dev/null @@ -1,105 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// - -/***************************************************************************** - * name: be_ai_weap.h - * - * desc: weapon AI - * - * $Archive: /source/code/botlib/be_ai_weap.h $ - * - *****************************************************************************/ - -//projectile flags -#define PFL_WINDOWDAMAGE 1 //projectile damages through window -#define PFL_RETURN 2 //set when projectile returns to owner -//weapon flags -#define WFL_FIRERELEASED 1 //set when projectile is fired with key-up event -//damage types -#define DAMAGETYPE_IMPACT 1 //damage on impact -#define DAMAGETYPE_RADIAL 2 //radial damage -#define DAMAGETYPE_VISIBLE 4 //damage to all entities visible to the projectile - -typedef struct projectileinfo_s -{ - char name[MAX_STRINGFIELD]; - char model[MAX_STRINGFIELD]; - int flags; - float gravity; - int damage; - float radius; - int visdamage; - int damagetype; - int healthinc; - float push; - float detonation; - float bounce; - float bouncefric; - float bouncestop; -} projectileinfo_t; - -typedef struct weaponinfo_s -{ - int valid; //true if the weapon info is valid - int number; //number of the weapon - char name[MAX_STRINGFIELD]; - char model[MAX_STRINGFIELD]; - int level; - int weaponindex; - int flags; - char projectile[MAX_STRINGFIELD]; - int numprojectiles; - float hspread; - float vspread; - float speed; - float acceleration; - vec3_t recoil; - vec3_t offset; - vec3_t angleoffset; - float extrazvelocity; - int ammoamount; - int ammoindex; - float activate; - float reload; - float spinup; - float spindown; - projectileinfo_t proj; //pointer to the used projectile -} weaponinfo_t; - -//setup the weapon AI -int BotSetupWeaponAI(void); -//shut down the weapon AI -void BotShutdownWeaponAI(void); -//returns the best weapon to fight with -int BotChooseBestFightWeapon(int weaponstate, int *inventory); -//returns the information of the current weapon -void BotGetWeaponInfo(int weaponstate, int weapon, weaponinfo_t *weaponinfo); -//loads the weapon weights -int BotLoadWeaponWeights(int weaponstate, char *filename); -//returns a handle to a newly allocated weapon state -int BotAllocWeaponState(void); -//frees the weapon state -void BotFreeWeaponState(int weaponstate); -//resets the whole weapon state -void BotResetWeaponState(int weaponstate); diff --git a/src/botlib/be_ai_weight.c b/src/botlib/be_ai_weight.c deleted file mode 100644 index 72c8206f..00000000 --- a/src/botlib/be_ai_weight.c +++ /dev/null @@ -1,913 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_ai_weight.c - * - * desc: fuzzy logic - * - * $Archive: /MissionPack/code/botlib/be_ai_weight.c $ - * - *****************************************************************************/ - -#include "../qcommon/q_shared.h" -#include "l_memory.h" -#include "l_log.h" -#include "l_utils.h" -#include "l_script.h" -#include "l_precomp.h" -#include "l_struct.h" -#include "l_libvar.h" -#include "aasfile.h" -#include "botlib.h" -#include "be_aas.h" -#include "be_aas_funcs.h" -#include "be_interface.h" -#include "be_ai_weight.h" - -#define MAX_INVENTORYVALUE 999999 -#define EVALUATERECURSIVELY - -#define MAX_WEIGHT_FILES 128 -weightconfig_t *weightFileList[MAX_WEIGHT_FILES]; - -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int ReadValue(source_t *source, float *value) -{ - token_t token; - - if (!PC_ExpectAnyToken(source, &token)) return qfalse; - if (!strcmp(token.string, "-")) - { - SourceWarning(source, "negative value set to zero\n"); - if (!PC_ExpectTokenType(source, TT_NUMBER, 0, &token)) return qfalse; - } //end if - if (token.type != TT_NUMBER) - { - SourceError(source, "invalid return value %s\n", token.string); - return qfalse; - } //end if - *value = token.floatvalue; - return qtrue; -} //end of the function ReadValue -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int ReadFuzzyWeight(source_t *source, fuzzyseperator_t *fs) -{ - if (PC_CheckTokenString(source, "balance")) - { - fs->type = WT_BALANCE; - if (!PC_ExpectTokenString(source, "(")) return qfalse; - if (!ReadValue(source, &fs->weight)) return qfalse; - if (!PC_ExpectTokenString(source, ",")) return qfalse; - if (!ReadValue(source, &fs->minweight)) return qfalse; - if (!PC_ExpectTokenString(source, ",")) return qfalse; - if (!ReadValue(source, &fs->maxweight)) return qfalse; - if (!PC_ExpectTokenString(source, ")")) return qfalse; - } //end if - else - { - fs->type = 0; - if (!ReadValue(source, &fs->weight)) return qfalse; - fs->minweight = fs->weight; - fs->maxweight = fs->weight; - } //end if - if (!PC_ExpectTokenString(source, ";")) return qfalse; - return qtrue; -} //end of the function ReadFuzzyWeight -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void FreeFuzzySeperators_r(fuzzyseperator_t *fs) -{ - if (!fs) return; - if (fs->child) FreeFuzzySeperators_r(fs->child); - if (fs->next) FreeFuzzySeperators_r(fs->next); - FreeMemory(fs); -} //end of the function FreeFuzzySeperators -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void FreeWeightConfig2(weightconfig_t *config) -{ - int i; - - for (i = 0; i < config->numweights; i++) - { - FreeFuzzySeperators_r(config->weights[i].firstseperator); - if (config->weights[i].name) FreeMemory(config->weights[i].name); - } //end for - FreeMemory(config); -} //end of the function FreeWeightConfig2 -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void FreeWeightConfig(weightconfig_t *config) -{ - if (!LibVarGetValue("bot_reloadcharacters")) return; - FreeWeightConfig2(config); -} //end of the function FreeWeightConfig -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -fuzzyseperator_t *ReadFuzzySeperators_r(source_t *source) -{ - int newindent, index, def, founddefault; - token_t token; - fuzzyseperator_t *fs, *lastfs, *firstfs; - - founddefault = qfalse; - firstfs = NULL; - lastfs = NULL; - if (!PC_ExpectTokenString(source, "(")) return NULL; - if (!PC_ExpectTokenType(source, TT_NUMBER, TT_INTEGER, &token)) return NULL; - index = token.intvalue; - if (!PC_ExpectTokenString(source, ")")) return NULL; - if (!PC_ExpectTokenString(source, "{")) return NULL; - if (!PC_ExpectAnyToken(source, &token)) return NULL; - do - { - def = !strcmp(token.string, "default"); - if (def || !strcmp(token.string, "case")) - { - fs = (fuzzyseperator_t *) GetClearedMemory(sizeof(fuzzyseperator_t)); - fs->index = index; - if (lastfs) lastfs->next = fs; - else firstfs = fs; - lastfs = fs; - if (def) - { - if (founddefault) - { - SourceError(source, "switch already has a default\n"); - FreeFuzzySeperators_r(firstfs); - return NULL; - } //end if - fs->value = MAX_INVENTORYVALUE; - founddefault = qtrue; - } //end if - else - { - if (!PC_ExpectTokenType(source, TT_NUMBER, TT_INTEGER, &token)) - { - FreeFuzzySeperators_r(firstfs); - return NULL; - } //end if - fs->value = token.intvalue; - } //end else - if (!PC_ExpectTokenString(source, ":") || !PC_ExpectAnyToken(source, &token)) - { - FreeFuzzySeperators_r(firstfs); - return NULL; - } //end if - newindent = qfalse; - if (!strcmp(token.string, "{")) - { - newindent = qtrue; - if (!PC_ExpectAnyToken(source, &token)) - { - FreeFuzzySeperators_r(firstfs); - return NULL; - } //end if - } //end if - if (!strcmp(token.string, "return")) - { - if (!ReadFuzzyWeight(source, fs)) - { - FreeFuzzySeperators_r(firstfs); - return NULL; - } //end if - } //end if - else if (!strcmp(token.string, "switch")) - { - fs->child = ReadFuzzySeperators_r(source); - if (!fs->child) - { - FreeFuzzySeperators_r(firstfs); - return NULL; - } //end if - } //end else if - else - { - SourceError(source, "invalid name %s\n", token.string); - return NULL; - } //end else - if (newindent) - { - if (!PC_ExpectTokenString(source, "}")) - { - FreeFuzzySeperators_r(firstfs); - return NULL; - } //end if - } //end if - } //end if - else - { - FreeFuzzySeperators_r(firstfs); - SourceError(source, "invalid name %s\n", token.string); - return NULL; - } //end else - if (!PC_ExpectAnyToken(source, &token)) - { - FreeFuzzySeperators_r(firstfs); - return NULL; - } //end if - } while(strcmp(token.string, "}")); - // - if (!founddefault) - { - SourceWarning(source, "switch without default\n"); - fs = (fuzzyseperator_t *) GetClearedMemory(sizeof(fuzzyseperator_t)); - fs->index = index; - fs->value = MAX_INVENTORYVALUE; - fs->weight = 0; - fs->next = NULL; - fs->child = NULL; - if (lastfs) lastfs->next = fs; - else firstfs = fs; - lastfs = fs; - } //end if - // - return firstfs; -} //end of the function ReadFuzzySeperators_r -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -weightconfig_t *ReadWeightConfig(char *filename) -{ - int newindent, avail = 0, n; - token_t token; - source_t *source; - fuzzyseperator_t *fs; - weightconfig_t *config = NULL; -#ifdef DEBUG - int starttime; - - starttime = Sys_MilliSeconds(); -#endif //DEBUG - - if (!LibVarGetValue("bot_reloadcharacters")) - { - avail = -1; - for( n = 0; n < MAX_WEIGHT_FILES; n++ ) - { - config = weightFileList[n]; - if( !config ) - { - if( avail == -1 ) - { - avail = n; - } //end if - continue; - } //end if - if( strcmp( filename, config->filename ) == 0 ) - { - //botimport.Print( PRT_MESSAGE, "retained %s\n", filename ); - return config; - } //end if - } //end for - - if( avail == -1 ) - { - botimport.Print( PRT_ERROR, "weightFileList was full trying to load %s\n", filename ); - return NULL; - } //end if - } //end if - - PC_SetBaseFolder(BOTFILESBASEFOLDER); - source = LoadSourceFile(filename); - if (!source) - { - botimport.Print(PRT_ERROR, "counldn't load %s\n", filename); - return NULL; - } //end if - // - config = (weightconfig_t *) GetClearedMemory(sizeof(weightconfig_t)); - config->numweights = 0; - Q_strncpyz( config->filename, filename, sizeof(config->filename) ); - //parse the item config file - while(PC_ReadToken(source, &token)) - { - if (!strcmp(token.string, "weight")) - { - if (config->numweights >= MAX_WEIGHTS) - { - SourceWarning(source, "too many fuzzy weights\n"); - break; - } //end if - if (!PC_ExpectTokenType(source, TT_STRING, 0, &token)) - { - FreeWeightConfig(config); - FreeSource(source); - return NULL; - } //end if - StripDoubleQuotes(token.string); - config->weights[config->numweights].name = (char *) GetClearedMemory(strlen(token.string) + 1); - strcpy(config->weights[config->numweights].name, token.string); - if (!PC_ExpectAnyToken(source, &token)) - { - FreeWeightConfig(config); - FreeSource(source); - return NULL; - } //end if - newindent = qfalse; - if (!strcmp(token.string, "{")) - { - newindent = qtrue; - if (!PC_ExpectAnyToken(source, &token)) - { - FreeWeightConfig(config); - FreeSource(source); - return NULL; - } //end if - } //end if - if (!strcmp(token.string, "switch")) - { - fs = ReadFuzzySeperators_r(source); - if (!fs) - { - FreeWeightConfig(config); - FreeSource(source); - return NULL; - } //end if - config->weights[config->numweights].firstseperator = fs; - } //end if - else if (!strcmp(token.string, "return")) - { - fs = (fuzzyseperator_t *) GetClearedMemory(sizeof(fuzzyseperator_t)); - fs->index = 0; - fs->value = MAX_INVENTORYVALUE; - fs->next = NULL; - fs->child = NULL; - if (!ReadFuzzyWeight(source, fs)) - { - FreeMemory(fs); - FreeWeightConfig(config); - FreeSource(source); - return NULL; - } //end if - config->weights[config->numweights].firstseperator = fs; - } //end else if - else - { - SourceError(source, "invalid name %s\n", token.string); - FreeWeightConfig(config); - FreeSource(source); - return NULL; - } //end else - if (newindent) - { - if (!PC_ExpectTokenString(source, "}")) - { - FreeWeightConfig(config); - FreeSource(source); - return NULL; - } //end if - } //end if - config->numweights++; - } //end if - else - { - SourceError(source, "invalid name %s\n", token.string); - FreeWeightConfig(config); - FreeSource(source); - return NULL; - } //end else - } //end while - //free the source at the end of a pass - FreeSource(source); - //if the file was located in a pak file - botimport.Print(PRT_MESSAGE, "loaded %s\n", filename); -#ifdef DEBUG - if (bot_developer) - { - botimport.Print(PRT_MESSAGE, "weights loaded in %d msec\n", Sys_MilliSeconds() - starttime); - } //end if -#endif //DEBUG - // - if (!LibVarGetValue("bot_reloadcharacters")) - { - weightFileList[avail] = config; - } //end if - // - return config; -} //end of the function ReadWeightConfig -#if 0 -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -qboolean WriteFuzzyWeight(FILE *fp, fuzzyseperator_t *fs) -{ - if (fs->type == WT_BALANCE) - { - if (fprintf(fp, " return balance(") < 0) return qfalse; - if (!WriteFloat(fp, fs->weight)) return qfalse; - if (fprintf(fp, ",") < 0) return qfalse; - if (!WriteFloat(fp, fs->minweight)) return qfalse; - if (fprintf(fp, ",") < 0) return qfalse; - if (!WriteFloat(fp, fs->maxweight)) return qfalse; - if (fprintf(fp, ");\n") < 0) return qfalse; - } //end if - else - { - if (fprintf(fp, " return ") < 0) return qfalse; - if (!WriteFloat(fp, fs->weight)) return qfalse; - if (fprintf(fp, ";\n") < 0) return qfalse; - } //end else - return qtrue; -} //end of the function WriteFuzzyWeight -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -qboolean WriteFuzzySeperators_r(FILE *fp, fuzzyseperator_t *fs, int indent) -{ - if (!WriteIndent(fp, indent)) return qfalse; - if (fprintf(fp, "switch(%d)\n", fs->index) < 0) return qfalse; - if (!WriteIndent(fp, indent)) return qfalse; - if (fprintf(fp, "{\n") < 0) return qfalse; - indent++; - do - { - if (!WriteIndent(fp, indent)) return qfalse; - if (fs->next) - { - if (fprintf(fp, "case %d:", fs->value) < 0) return qfalse; - } //end if - else - { - if (fprintf(fp, "default:") < 0) return qfalse; - } //end else - if (fs->child) - { - if (fprintf(fp, "\n") < 0) return qfalse; - if (!WriteIndent(fp, indent)) return qfalse; - if (fprintf(fp, "{\n") < 0) return qfalse; - if (!WriteFuzzySeperators_r(fp, fs->child, indent + 1)) return qfalse; - if (!WriteIndent(fp, indent)) return qfalse; - if (fs->next) - { - if (fprintf(fp, "} //end case\n") < 0) return qfalse; - } //end if - else - { - if (fprintf(fp, "} //end default\n") < 0) return qfalse; - } //end else - } //end if - else - { - if (!WriteFuzzyWeight(fp, fs)) return qfalse; - } //end else - fs = fs->next; - } while(fs); - indent--; - if (!WriteIndent(fp, indent)) return qfalse; - if (fprintf(fp, "} //end switch\n") < 0) return qfalse; - return qtrue; -} //end of the function WriteItemFuzzyWeights_r -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -qboolean WriteWeightConfig(char *filename, weightconfig_t *config) -{ - int i; - FILE *fp; - weight_t *ifw; - - fp = fopen(filename, "wb"); - if (!fp) return qfalse; - - for (i = 0; i < config->numweights; i++) - { - ifw = &config->weights[i]; - if (fprintf(fp, "\nweight \"%s\"\n", ifw->name) < 0) return qfalse; - if (fprintf(fp, "{\n") < 0) return qfalse; - if (ifw->firstseperator->index > 0) - { - if (!WriteFuzzySeperators_r(fp, ifw->firstseperator, 1)) return qfalse; - } //end if - else - { - if (!WriteIndent(fp, 1)) return qfalse; - if (!WriteFuzzyWeight(fp, ifw->firstseperator)) return qfalse; - } //end else - if (fprintf(fp, "} //end weight\n") < 0) return qfalse; - } //end for - fclose(fp); - return qtrue; -} //end of the function WriteWeightConfig -#endif -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int FindFuzzyWeight(weightconfig_t *wc, char *name) -{ - int i; - - for (i = 0; i < wc->numweights; i++) - { - if (!strcmp(wc->weights[i].name, name)) - { - return i; - } //end if - } //end if - return -1; -} //end of the function FindFuzzyWeight -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -float FuzzyWeight_r(int *inventory, fuzzyseperator_t *fs) -{ - float scale, w1, w2; - - if (inventory[fs->index] < fs->value) - { - if (fs->child) return FuzzyWeight_r(inventory, fs->child); - else return fs->weight; - } //end if - else if (fs->next) - { - if (inventory[fs->index] < fs->next->value) - { - //first weight - if (fs->child) w1 = FuzzyWeight_r(inventory, fs->child); - else w1 = fs->weight; - //second weight - if (fs->next->child) w2 = FuzzyWeight_r(inventory, fs->next->child); - else w2 = fs->next->weight; - //the scale factor - scale = (inventory[fs->index] - fs->value) / (fs->next->value - fs->value); - //scale between the two weights - return scale * w1 + (1 - scale) * w2; - } //end if - return FuzzyWeight_r(inventory, fs->next); - } //end else if - return fs->weight; -} //end of the function FuzzyWeight_r -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -float FuzzyWeightUndecided_r(int *inventory, fuzzyseperator_t *fs) -{ - float scale, w1, w2; - - if (inventory[fs->index] < fs->value) - { - if (fs->child) return FuzzyWeightUndecided_r(inventory, fs->child); - else return fs->minweight + random() * (fs->maxweight - fs->minweight); - } //end if - else if (fs->next) - { - if (inventory[fs->index] < fs->next->value) - { - //first weight - if (fs->child) w1 = FuzzyWeightUndecided_r(inventory, fs->child); - else w1 = fs->minweight + random() * (fs->maxweight - fs->minweight); - //second weight - if (fs->next->child) w2 = FuzzyWeight_r(inventory, fs->next->child); - else w2 = fs->next->minweight + random() * (fs->next->maxweight - fs->next->minweight); - //the scale factor - scale = (inventory[fs->index] - fs->value) / (fs->next->value - fs->value); - //scale between the two weights - return scale * w1 + (1 - scale) * w2; - } //end if - return FuzzyWeightUndecided_r(inventory, fs->next); - } //end else if - return fs->weight; -} //end of the function FuzzyWeightUndecided_r -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -float FuzzyWeight(int *inventory, weightconfig_t *wc, int weightnum) -{ -#ifdef EVALUATERECURSIVELY - return FuzzyWeight_r(inventory, wc->weights[weightnum].firstseperator); -#else - fuzzyseperator_t *s; - - s = wc->weights[weightnum].firstseperator; - if (!s) return 0; - while(1) - { - if (inventory[s->index] < s->value) - { - if (s->child) s = s->child; - else return s->weight; - } //end if - else - { - if (s->next) s = s->next; - else return s->weight; - } //end else - } //end if - return 0; -#endif -} //end of the function FuzzyWeight -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -float FuzzyWeightUndecided(int *inventory, weightconfig_t *wc, int weightnum) -{ -#ifdef EVALUATERECURSIVELY - return FuzzyWeightUndecided_r(inventory, wc->weights[weightnum].firstseperator); -#else - fuzzyseperator_t *s; - - s = wc->weights[weightnum].firstseperator; - if (!s) return 0; - while(1) - { - if (inventory[s->index] < s->value) - { - if (s->child) s = s->child; - else return s->minweight + random() * (s->maxweight - s->minweight); - } //end if - else - { - if (s->next) s = s->next; - else return s->minweight + random() * (s->maxweight - s->minweight); - } //end else - } //end if - return 0; -#endif -} //end of the function FuzzyWeightUndecided -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void EvolveFuzzySeperator_r(fuzzyseperator_t *fs) -{ - if (fs->child) - { - EvolveFuzzySeperator_r(fs->child); - } //end if - else if (fs->type == WT_BALANCE) - { - //every once in a while an evolution leap occurs, mutation - if (random() < 0.01) fs->weight += crandom() * (fs->maxweight - fs->minweight); - else fs->weight += crandom() * (fs->maxweight - fs->minweight) * 0.5; - //modify bounds if necesary because of mutation - if (fs->weight < fs->minweight) fs->minweight = fs->weight; - else if (fs->weight > fs->maxweight) fs->maxweight = fs->weight; - } //end else if - if (fs->next) EvolveFuzzySeperator_r(fs->next); -} //end of the function EvolveFuzzySeperator_r -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void EvolveWeightConfig(weightconfig_t *config) -{ - int i; - - for (i = 0; i < config->numweights; i++) - { - EvolveFuzzySeperator_r(config->weights[i].firstseperator); - } //end for -} //end of the function EvolveWeightConfig -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void ScaleFuzzySeperator_r(fuzzyseperator_t *fs, float scale) -{ - if (fs->child) - { - ScaleFuzzySeperator_r(fs->child, scale); - } //end if - else if (fs->type == WT_BALANCE) - { - // - fs->weight = (fs->maxweight + fs->minweight) * scale; - //get the weight between bounds - if (fs->weight < fs->minweight) fs->weight = fs->minweight; - else if (fs->weight > fs->maxweight) fs->weight = fs->maxweight; - } //end else if - if (fs->next) ScaleFuzzySeperator_r(fs->next, scale); -} //end of the function ScaleFuzzySeperator_r -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void ScaleWeight(weightconfig_t *config, char *name, float scale) -{ - int i; - - if (scale < 0) scale = 0; - else if (scale > 1) scale = 1; - for (i = 0; i < config->numweights; i++) - { - if (!strcmp(name, config->weights[i].name)) - { - ScaleFuzzySeperator_r(config->weights[i].firstseperator, scale); - break; - } //end if - } //end for -} //end of the function ScaleWeight -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void ScaleFuzzySeperatorBalanceRange_r(fuzzyseperator_t *fs, float scale) -{ - if (fs->child) - { - ScaleFuzzySeperatorBalanceRange_r(fs->child, scale); - } //end if - else if (fs->type == WT_BALANCE) - { - float mid = (fs->minweight + fs->maxweight) * 0.5; - //get the weight between bounds - fs->maxweight = mid + (fs->maxweight - mid) * scale; - fs->minweight = mid + (fs->minweight - mid) * scale; - if (fs->maxweight < fs->minweight) - { - fs->maxweight = fs->minweight; - } //end if - } //end else if - if (fs->next) ScaleFuzzySeperatorBalanceRange_r(fs->next, scale); -} //end of the function ScaleFuzzySeperatorBalanceRange_r -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void ScaleFuzzyBalanceRange(weightconfig_t *config, float scale) -{ - int i; - - if (scale < 0) scale = 0; - else if (scale > 100) scale = 100; - for (i = 0; i < config->numweights; i++) - { - ScaleFuzzySeperatorBalanceRange_r(config->weights[i].firstseperator, scale); - } //end for -} //end of the function ScaleFuzzyBalanceRange -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int InterbreedFuzzySeperator_r(fuzzyseperator_t *fs1, fuzzyseperator_t *fs2, - fuzzyseperator_t *fsout) -{ - if (fs1->child) - { - if (!fs2->child || !fsout->child) - { - botimport.Print(PRT_ERROR, "cannot interbreed weight configs, unequal child\n"); - return qfalse; - } //end if - if (!InterbreedFuzzySeperator_r(fs2->child, fs2->child, fsout->child)) - { - return qfalse; - } //end if - } //end if - else if (fs1->type == WT_BALANCE) - { - if (fs2->type != WT_BALANCE || fsout->type != WT_BALANCE) - { - botimport.Print(PRT_ERROR, "cannot interbreed weight configs, unequal balance\n"); - return qfalse; - } //end if - fsout->weight = (fs1->weight + fs2->weight) / 2; - if (fsout->weight > fsout->maxweight) fsout->maxweight = fsout->weight; - if (fsout->weight > fsout->minweight) fsout->minweight = fsout->weight; - } //end else if - if (fs1->next) - { - if (!fs2->next || !fsout->next) - { - botimport.Print(PRT_ERROR, "cannot interbreed weight configs, unequal next\n"); - return qfalse; - } //end if - if (!InterbreedFuzzySeperator_r(fs1->next, fs2->next, fsout->next)) - { - return qfalse; - } //end if - } //end if - return qtrue; -} //end of the function InterbreedFuzzySeperator_r -//=========================================================================== -// config1 and config2 are interbreeded and stored in configout -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void InterbreedWeightConfigs(weightconfig_t *config1, weightconfig_t *config2, - weightconfig_t *configout) -{ - int i; - - if (config1->numweights != config2->numweights || - config1->numweights != configout->numweights) - { - botimport.Print(PRT_ERROR, "cannot interbreed weight configs, unequal numweights\n"); - return; - } //end if - for (i = 0; i < config1->numweights; i++) - { - InterbreedFuzzySeperator_r(config1->weights[i].firstseperator, - config2->weights[i].firstseperator, - configout->weights[i].firstseperator); - } //end for -} //end of the function InterbreedWeightConfigs -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void BotShutdownWeights(void) -{ - int i; - - for( i = 0; i < MAX_WEIGHT_FILES; i++ ) - { - if (weightFileList[i]) - { - FreeWeightConfig2(weightFileList[i]); - weightFileList[i] = NULL; - } //end if - } //end for -} //end of the function BotShutdownWeights diff --git a/src/botlib/be_ai_weight.h b/src/botlib/be_ai_weight.h deleted file mode 100644 index 46445df9..00000000 --- a/src/botlib/be_ai_weight.h +++ /dev/null @@ -1,84 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_ai_weight.h - * - * desc: fuzzy weights - * - * $Archive: /source/code/botlib/be_ai_weight.h $ - * - *****************************************************************************/ - -#define WT_BALANCE 1 -#define MAX_WEIGHTS 128 - -//fuzzy seperator -typedef struct fuzzyseperator_s -{ - int index; - int value; - int type; - float weight; - float minweight; - float maxweight; - struct fuzzyseperator_s *child; - struct fuzzyseperator_s *next; -} fuzzyseperator_t; - -//fuzzy weight -typedef struct weight_s -{ - char *name; - struct fuzzyseperator_s *firstseperator; -} weight_t; - -//weight configuration -typedef struct weightconfig_s -{ - int numweights; - weight_t weights[MAX_WEIGHTS]; - char filename[MAX_QPATH]; -} weightconfig_t; - -//reads a weight configuration -weightconfig_t *ReadWeightConfig(char *filename); -//free a weight configuration -void FreeWeightConfig(weightconfig_t *config); -//writes a weight configuration, returns true if successfull -qboolean WriteWeightConfig(char *filename, weightconfig_t *config); -//find the fuzzy weight with the given name -int FindFuzzyWeight(weightconfig_t *wc, char *name); -//returns the fuzzy weight for the given inventory and weight -float FuzzyWeight(int *inventory, weightconfig_t *wc, int weightnum); -float FuzzyWeightUndecided(int *inventory, weightconfig_t *wc, int weightnum); -//scales the weight with the given name -void ScaleWeight(weightconfig_t *config, char *name, float scale); -//scale the balance range -void ScaleBalanceRange(weightconfig_t *config, float scale); -//evolves the weight configuration -void EvolveWeightConfig(weightconfig_t *config); -//interbreed the weight configurations and stores the interbreeded one in configout -void InterbreedWeightConfigs(weightconfig_t *config1, weightconfig_t *config2, weightconfig_t *configout); -//frees cached weight configurations -void BotShutdownWeights(void); diff --git a/src/botlib/be_ea.c b/src/botlib/be_ea.c deleted file mode 100644 index 933274bd..00000000 --- a/src/botlib/be_ea.c +++ /dev/null @@ -1,509 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_ea.c - * - * desc: elementary actions - * - * $Archive: /MissionPack/code/botlib/be_ea.c $ - * - *****************************************************************************/ - -#include "../qcommon/q_shared.h" -#include "l_memory.h" -#include "l_script.h" -#include "l_precomp.h" -#include "l_struct.h" -#include "botlib.h" -#include "be_interface.h" - -#define MAX_USERMOVE 400 -#define MAX_COMMANDARGUMENTS 10 -#define ACTION_JUMPEDLASTFRAME 128 - -bot_input_t *botinputs; - -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void EA_Say(int client, char *str) -{ - botimport.BotClientCommand(client, va("say %s", str) ); -} //end of the function EA_Say -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void EA_SayTeam(int client, char *str) -{ - botimport.BotClientCommand(client, va("say_team %s", str)); -} //end of the function EA_SayTeam -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void EA_Tell(int client, int clientto, char *str) -{ - botimport.BotClientCommand(client, va("tell %d, %s", clientto, str)); -} //end of the function EA_SayTeam -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void EA_UseItem(int client, char *it) -{ - botimport.BotClientCommand(client, va("use %s", it)); -} //end of the function EA_UseItem -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void EA_DropItem(int client, char *it) -{ - botimport.BotClientCommand(client, va("drop %s", it)); -} //end of the function EA_DropItem -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void EA_UseInv(int client, char *inv) -{ - botimport.BotClientCommand(client, va("invuse %s", inv)); -} //end of the function EA_UseInv -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void EA_DropInv(int client, char *inv) -{ - botimport.BotClientCommand(client, va("invdrop %s", inv)); -} //end of the function EA_DropInv -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void EA_Gesture(int client) -{ - bot_input_t *bi; - - bi = &botinputs[client]; - - bi->actionflags |= ACTION_GESTURE; -} //end of the function EA_Gesture -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void EA_Command(int client, char *command) -{ - botimport.BotClientCommand(client, command); -} //end of the function EA_Command -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void EA_SelectWeapon(int client, int weapon) -{ - bot_input_t *bi; - - bi = &botinputs[client]; - - bi->weapon = weapon; -} //end of the function EA_SelectWeapon -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void EA_Attack(int client) -{ - bot_input_t *bi; - - bi = &botinputs[client]; - - bi->actionflags |= ACTION_ATTACK; -} //end of the function EA_Attack -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void EA_Talk(int client) -{ - bot_input_t *bi; - - bi = &botinputs[client]; - - bi->actionflags |= ACTION_TALK; -} //end of the function EA_Talk -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void EA_Use(int client) -{ - bot_input_t *bi; - - bi = &botinputs[client]; - - bi->actionflags |= ACTION_USE; -} //end of the function EA_Use -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void EA_Respawn(int client) -{ - bot_input_t *bi; - - bi = &botinputs[client]; - - bi->actionflags |= ACTION_RESPAWN; -} //end of the function EA_Respawn -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void EA_Jump(int client) -{ - bot_input_t *bi; - - bi = &botinputs[client]; - - if (bi->actionflags & ACTION_JUMPEDLASTFRAME) - { - bi->actionflags &= ~ACTION_JUMP; - } //end if - else - { - bi->actionflags |= ACTION_JUMP; - } //end if -} //end of the function EA_Jump -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void EA_DelayedJump(int client) -{ - bot_input_t *bi; - - bi = &botinputs[client]; - - if (bi->actionflags & ACTION_JUMPEDLASTFRAME) - { - bi->actionflags &= ~ACTION_DELAYEDJUMP; - } //end if - else - { - bi->actionflags |= ACTION_DELAYEDJUMP; - } //end if -} //end of the function EA_DelayedJump -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void EA_Crouch(int client) -{ - bot_input_t *bi; - - bi = &botinputs[client]; - - bi->actionflags |= ACTION_CROUCH; -} //end of the function EA_Crouch -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void EA_Walk(int client) -{ - bot_input_t *bi; - - bi = &botinputs[client]; - - bi->actionflags |= ACTION_WALK; -} //end of the function EA_Walk -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void EA_Action(int client, int action) -{ - bot_input_t *bi; - - bi = &botinputs[client]; - - bi->actionflags |= action; -} //end of function EA_Action -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void EA_MoveUp(int client) -{ - bot_input_t *bi; - - bi = &botinputs[client]; - - bi->actionflags |= ACTION_MOVEUP; -} //end of the function EA_MoveUp -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void EA_MoveDown(int client) -{ - bot_input_t *bi; - - bi = &botinputs[client]; - - bi->actionflags |= ACTION_MOVEDOWN; -} //end of the function EA_MoveDown -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void EA_MoveForward(int client) -{ - bot_input_t *bi; - - bi = &botinputs[client]; - - bi->actionflags |= ACTION_MOVEFORWARD; -} //end of the function EA_MoveForward -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void EA_MoveBack(int client) -{ - bot_input_t *bi; - - bi = &botinputs[client]; - - bi->actionflags |= ACTION_MOVEBACK; -} //end of the function EA_MoveBack -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void EA_MoveLeft(int client) -{ - bot_input_t *bi; - - bi = &botinputs[client]; - - bi->actionflags |= ACTION_MOVELEFT; -} //end of the function EA_MoveLeft -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void EA_MoveRight(int client) -{ - bot_input_t *bi; - - bi = &botinputs[client]; - - bi->actionflags |= ACTION_MOVERIGHT; -} //end of the function EA_MoveRight -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void EA_Move(int client, vec3_t dir, float speed) -{ - bot_input_t *bi; - - bi = &botinputs[client]; - - VectorCopy(dir, bi->dir); - //cap speed - if (speed > MAX_USERMOVE) speed = MAX_USERMOVE; - else if (speed < -MAX_USERMOVE) speed = -MAX_USERMOVE; - bi->speed = speed; -} //end of the function EA_Move -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void EA_View(int client, vec3_t viewangles) -{ - bot_input_t *bi; - - bi = &botinputs[client]; - - VectorCopy(viewangles, bi->viewangles); -} //end of the function EA_View -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void EA_EndRegular(int client, float thinktime) -{ -/* - bot_input_t *bi; - int jumped = qfalse; - - bi = &botinputs[client]; - - bi->actionflags &= ~ACTION_JUMPEDLASTFRAME; - - bi->thinktime = thinktime; - botimport.BotInput(client, bi); - - bi->thinktime = 0; - VectorClear(bi->dir); - bi->speed = 0; - jumped = bi->actionflags & ACTION_JUMP; - bi->actionflags = 0; - if (jumped) bi->actionflags |= ACTION_JUMPEDLASTFRAME; -*/ -} //end of the function EA_EndRegular -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void EA_GetInput(int client, float thinktime, bot_input_t *input) -{ - bot_input_t *bi; -// int jumped = qfalse; - - bi = &botinputs[client]; - -// bi->actionflags &= ~ACTION_JUMPEDLASTFRAME; - - bi->thinktime = thinktime; - Com_Memcpy(input, bi, sizeof(bot_input_t)); - - /* - bi->thinktime = 0; - VectorClear(bi->dir); - bi->speed = 0; - jumped = bi->actionflags & ACTION_JUMP; - bi->actionflags = 0; - if (jumped) bi->actionflags |= ACTION_JUMPEDLASTFRAME; - */ -} //end of the function EA_GetInput -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void EA_ResetInput(int client) -{ - bot_input_t *bi; - int jumped = qfalse; - - bi = &botinputs[client]; - bi->actionflags &= ~ACTION_JUMPEDLASTFRAME; - - bi->thinktime = 0; - VectorClear(bi->dir); - bi->speed = 0; - jumped = bi->actionflags & ACTION_JUMP; - bi->actionflags = 0; - if (jumped) bi->actionflags |= ACTION_JUMPEDLASTFRAME; -} //end of the function EA_ResetInput -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int EA_Setup(void) -{ - //initialize the bot inputs - botinputs = (bot_input_t *) GetClearedHunkMemory( - botlibglobals.maxclients * sizeof(bot_input_t)); - return BLERR_NOERROR; -} //end of the function EA_Setup -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void EA_Shutdown(void) -{ - FreeMemory(botinputs); - botinputs = NULL; -} //end of the function EA_Shutdown diff --git a/src/botlib/be_ea.h b/src/botlib/be_ea.h deleted file mode 100644 index 8aac7957..00000000 --- a/src/botlib/be_ea.h +++ /dev/null @@ -1,67 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// - -/***************************************************************************** - * name: be_ea.h - * - * desc: elementary actions - * - * $Archive: /source/code/botlib/be_ea.h $ - * - *****************************************************************************/ - -//ClientCommand elementary actions -void EA_Say(int client, char *str); -void EA_SayTeam(int client, char *str); -void EA_Command(int client, char *command ); - -void EA_Action(int client, int action); -void EA_Crouch(int client); -void EA_Walk(int client); -void EA_MoveUp(int client); -void EA_MoveDown(int client); -void EA_MoveForward(int client); -void EA_MoveBack(int client); -void EA_MoveLeft(int client); -void EA_MoveRight(int client); -void EA_Attack(int client); -void EA_Respawn(int client); -void EA_Talk(int client); -void EA_Gesture(int client); -void EA_Use(int client); - -//regular elementary actions -void EA_SelectWeapon(int client, int weapon); -void EA_Jump(int client); -void EA_DelayedJump(int client); -void EA_Move(int client, vec3_t dir, float speed); -void EA_View(int client, vec3_t viewangles); - -//send regular input to the server -void EA_EndRegular(int client, float thinktime); -void EA_GetInput(int client, float thinktime, bot_input_t *input); -void EA_ResetInput(int client); -//setup and shutdown routines -int EA_Setup(void); -void EA_Shutdown(void); diff --git a/src/botlib/be_interface.c b/src/botlib/be_interface.c deleted file mode 100644 index 2980674e..00000000 --- a/src/botlib/be_interface.c +++ /dev/null @@ -1,896 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_interface.c // bk010221 - FIXME - DEAD code elimination - * - * desc: bot library interface - * - * $Archive: /MissionPack/code/botlib/be_interface.c $ - * - *****************************************************************************/ - -#include "../qcommon/q_shared.h" -#include "l_memory.h" -#include "l_log.h" -#include "l_libvar.h" -#include "l_script.h" -#include "l_precomp.h" -#include "l_struct.h" -#include "aasfile.h" -#include "botlib.h" -#include "be_aas.h" -#include "be_aas_funcs.h" -#include "be_aas_def.h" -#include "be_interface.h" - -#include "be_ea.h" -#include "be_ai_weight.h" -#include "be_ai_goal.h" -#include "be_ai_move.h" -#include "be_ai_weap.h" -#include "be_ai_chat.h" -#include "be_ai_char.h" -#include "be_ai_gen.h" - -//library globals in a structure -botlib_globals_t botlibglobals; - -botlib_export_t be_botlib_export; -botlib_import_t botimport; -// -int bot_developer; -//qtrue if the library is setup -int botlibsetup = qfalse; - -//=========================================================================== -// -// several functions used by the exported functions -// -//=========================================================================== - -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int Sys_MilliSeconds(void) -{ - return clock() * 1000 / CLOCKS_PER_SEC; -} //end of the function Sys_MilliSeconds -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -qboolean ValidClientNumber(int num, char *str) -{ - if (num < 0 || num > botlibglobals.maxclients) - { - //weird: the disabled stuff results in a crash - botimport.Print(PRT_ERROR, "%s: invalid client number %d, [0, %d]\n", - str, num, botlibglobals.maxclients); - return qfalse; - } //end if - return qtrue; -} //end of the function BotValidateClientNumber -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -qboolean ValidEntityNumber(int num, char *str) -{ - if (num < 0 || num > botlibglobals.maxentities) - { - botimport.Print(PRT_ERROR, "%s: invalid entity number %d, [0, %d]\n", - str, num, botlibglobals.maxentities); - return qfalse; - } //end if - return qtrue; -} //end of the function BotValidateClientNumber -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -qboolean BotLibSetup(char *str) -{ - if (!botlibglobals.botlibsetup) - { - botimport.Print(PRT_ERROR, "%s: bot library used before being setup\n", str); - return qfalse; - } //end if - return qtrue; -} //end of the function BotLibSetup - -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int Export_BotLibSetup(void) -{ - int errnum; - char logfilename[MAX_QPATH]; - char *homedir, *gamedir; - - bot_developer = LibVarGetValue("bot_developer"); - memset( &botlibglobals, 0, sizeof(botlibglobals) ); // bk001207 - init - //initialize byte swapping (litte endian etc.) -// Swap_Init(); - homedir = LibVarGetString("homedir"); - gamedir = LibVarGetString("gamedir"); - if (homedir[0]) { - if (gamedir[0]) { - Com_sprintf(logfilename, sizeof(logfilename), "%s%c%s%cbotlib.log", homedir, PATH_SEP, gamedir, PATH_SEP); - } - else { - /*Com_sprintf(logfilename, sizeof(logfilename), "%s%c" BASEGAME "%cbotlib.log", homedir, PATH_SEP, PATH_SEP);*/ - } - } else { - Com_sprintf(logfilename, sizeof(logfilename), "botlib.log"); - } - Log_Open(logfilename); - // - botimport.Print(PRT_MESSAGE, "------- BotLib Initialization -------\n"); - // - botlibglobals.maxclients = (int) LibVarValue("maxclients", "128"); - botlibglobals.maxentities = (int) LibVarValue("maxentities", "1024"); - - errnum = AAS_Setup(); //be_aas_main.c - if (errnum != BLERR_NOERROR) return errnum; - errnum = EA_Setup(); //be_ea.c - if (errnum != BLERR_NOERROR) return errnum; - errnum = BotSetupWeaponAI(); //be_ai_weap.c - if (errnum != BLERR_NOERROR)return errnum; - errnum = BotSetupGoalAI(); //be_ai_goal.c - if (errnum != BLERR_NOERROR) return errnum; - errnum = BotSetupChatAI(); //be_ai_chat.c - if (errnum != BLERR_NOERROR) return errnum; - errnum = BotSetupMoveAI(); //be_ai_move.c - if (errnum != BLERR_NOERROR) return errnum; - - botlibsetup = qtrue; - botlibglobals.botlibsetup = qtrue; - - return BLERR_NOERROR; -} //end of the function Export_BotLibSetup -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int Export_BotLibShutdown(void) -{ - if (!BotLibSetup("BotLibShutdown")) return BLERR_LIBRARYNOTSETUP; -#ifndef DEMO - //DumpFileCRCs(); -#endif //DEMO - // - BotShutdownChatAI(); //be_ai_chat.c - BotShutdownMoveAI(); //be_ai_move.c - BotShutdownGoalAI(); //be_ai_goal.c - BotShutdownWeaponAI(); //be_ai_weap.c - BotShutdownWeights(); //be_ai_weight.c - BotShutdownCharacters(); //be_ai_char.c - //shud down aas - AAS_Shutdown(); - //shut down bot elemantary actions - EA_Shutdown(); - //free all libvars - LibVarDeAllocAll(); - //remove all global defines from the pre compiler - PC_RemoveAllGlobalDefines(); - - //dump all allocated memory -// DumpMemory(); -#ifdef DEBUG - PrintMemoryLabels(); -#endif - //shut down library log file - Log_Shutdown(); - // - botlibsetup = qfalse; - botlibglobals.botlibsetup = qfalse; - // print any files still open - PC_CheckOpenSourceHandles(); - // - return BLERR_NOERROR; -} //end of the function Export_BotLibShutdown -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int Export_BotLibVarSet(char *var_name, char *value) -{ - LibVarSet(var_name, value); - return BLERR_NOERROR; -} //end of the function Export_BotLibVarSet -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int Export_BotLibVarGet(char *var_name, char *value, int size) -{ - char *varvalue; - - varvalue = LibVarGetString(var_name); - strncpy(value, varvalue, size-1); - value[size-1] = '\0'; - return BLERR_NOERROR; -} //end of the function Export_BotLibVarGet -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int Export_BotLibStartFrame(float time) -{ - if (!BotLibSetup("BotStartFrame")) return BLERR_LIBRARYNOTSETUP; - return AAS_StartFrame(time); -} //end of the function Export_BotLibStartFrame -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int Export_BotLibLoadMap(const char *mapname) -{ -#ifdef DEBUG - int starttime = Sys_MilliSeconds(); -#endif - int errnum; - - if (!BotLibSetup("BotLoadMap")) return BLERR_LIBRARYNOTSETUP; - // - botimport.Print(PRT_MESSAGE, "------------ Map Loading ------------\n"); - //startup AAS for the current map, model and sound index - errnum = AAS_LoadMap(mapname); - if (errnum != BLERR_NOERROR) return errnum; - //initialize the items in the level - BotInitLevelItems(); //be_ai_goal.h - BotSetBrushModelTypes(); //be_ai_move.h - // - botimport.Print(PRT_MESSAGE, "-------------------------------------\n"); -#ifdef DEBUG - botimport.Print(PRT_MESSAGE, "map loaded in %d msec\n", Sys_MilliSeconds() - starttime); -#endif - // - return BLERR_NOERROR; -} //end of the function Export_BotLibLoadMap -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int Export_BotLibUpdateEntity(int ent, bot_entitystate_t *state) -{ - if (!BotLibSetup("BotUpdateEntity")) return BLERR_LIBRARYNOTSETUP; - if (!ValidEntityNumber(ent, "BotUpdateEntity")) return BLERR_INVALIDENTITYNUMBER; - - return AAS_UpdateEntity(ent, state); -} //end of the function Export_BotLibUpdateEntity -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_TestMovementPrediction(int entnum, vec3_t origin, vec3_t dir); -void ElevatorBottomCenter(aas_reachability_t *reach, vec3_t bottomcenter); -int BotGetReachabilityToGoal(vec3_t origin, int areanum, - int lastgoalareanum, int lastareanum, - int *avoidreach, float *avoidreachtimes, int *avoidreachtries, - bot_goal_t *goal, int travelflags, int movetravelflags, - struct bot_avoidspot_s *avoidspots, int numavoidspots, int *flags); - -int AAS_PointLight(vec3_t origin, int *red, int *green, int *blue); - -int AAS_TraceAreas(vec3_t start, vec3_t end, int *areas, vec3_t *points, int maxareas); - -int AAS_Reachability_WeaponJump(int area1num, int area2num); - -int BotFuzzyPointReachabilityArea(vec3_t origin); - -float BotGapDistance(vec3_t origin, vec3_t hordir, int entnum); - -void AAS_FloodAreas(vec3_t origin); - -int BotExportTest(int parm0, char *parm1, vec3_t parm2, vec3_t parm3) -{ - -// return AAS_PointLight(parm2, NULL, NULL, NULL); - -#ifdef DEBUG - static int area = -1; - static int line[2]; - int newarea, i, highlightarea, flood; -// int reachnum; - vec3_t eye, forward, right, end, origin; -// vec3_t bottomcenter; -// aas_trace_t trace; -// aas_face_t *face; -// aas_entity_t *ent; -// bsp_trace_t bsptrace; -// aas_reachability_t reach; -// bot_goal_t goal; - - // clock_t start_time, end_time; - vec3_t mins = {-16, -16, -24}; - vec3_t maxs = {16, 16, 32}; - -// int areas[10], numareas; - - - //return 0; - - if (!aasworld.loaded) return 0; - - /* - if (parm0 & 1) - { - AAS_ClearShownPolygons(); - AAS_FloodAreas(parm2); - } //end if - return 0; - */ - for (i = 0; i < 2; i++) if (!line[i]) line[i] = botimport.DebugLineCreate(); - -// AAS_ClearShownDebugLines(); - - //if (AAS_AgainstLadder(parm2)) botimport.Print(PRT_MESSAGE, "against ladder\n"); - //BotOnGround(parm2, PRESENCE_NORMAL, 1, &newarea, &newarea); - //botimport.Print(PRT_MESSAGE, "%f %f %f\n", parm2[0], parm2[1], parm2[2]); - //* - highlightarea = LibVarGetValue("bot_highlightarea"); - if (highlightarea > 0) - { - newarea = highlightarea; - } //end if - else - { - VectorCopy(parm2, origin); - origin[2] += 0.5; - //newarea = AAS_PointAreaNum(origin); - newarea = BotFuzzyPointReachabilityArea(origin); - } //end else - - botimport.Print(PRT_MESSAGE, "\rtravel time to goal (%d) = %d ", botlibglobals.goalareanum, - AAS_AreaTravelTimeToGoalArea(newarea, origin, botlibglobals.goalareanum, TFL_DEFAULT)); - //newarea = BotReachabilityArea(origin, qtrue); - if (newarea != area) - { - botimport.Print(PRT_MESSAGE, "origin = %f, %f, %f\n", origin[0], origin[1], origin[2]); - area = newarea; - botimport.Print(PRT_MESSAGE, "new area %d, cluster %d, presence type %d\n", - area, AAS_AreaCluster(area), AAS_PointPresenceType(origin)); - botimport.Print(PRT_MESSAGE, "area contents: "); - if (aasworld.areasettings[area].contents & AREACONTENTS_WATER) - { - botimport.Print(PRT_MESSAGE, "water &"); - } //end if - if (aasworld.areasettings[area].contents & AREACONTENTS_LAVA) - { - botimport.Print(PRT_MESSAGE, "lava &"); - } //end if - if (aasworld.areasettings[area].contents & AREACONTENTS_SLIME) - { - botimport.Print(PRT_MESSAGE, "slime &"); - } //end if - if (aasworld.areasettings[area].contents & AREACONTENTS_JUMPPAD) - { - botimport.Print(PRT_MESSAGE, "jump pad &"); - } //end if - if (aasworld.areasettings[area].contents & AREACONTENTS_CLUSTERPORTAL) - { - botimport.Print(PRT_MESSAGE, "cluster portal &"); - } //end if - if (aasworld.areasettings[area].contents & AREACONTENTS_VIEWPORTAL) - { - botimport.Print(PRT_MESSAGE, "view portal &"); - } //end if - if (aasworld.areasettings[area].contents & AREACONTENTS_DONOTENTER) - { - botimport.Print(PRT_MESSAGE, "do not enter &"); - } //end if - if (aasworld.areasettings[area].contents & AREACONTENTS_MOVER) - { - botimport.Print(PRT_MESSAGE, "mover &"); - } //end if - if (!aasworld.areasettings[area].contents) - { - botimport.Print(PRT_MESSAGE, "empty"); - } //end if - botimport.Print(PRT_MESSAGE, "\n"); - botimport.Print(PRT_MESSAGE, "travel time to goal (%d) = %d\n", botlibglobals.goalareanum, - AAS_AreaTravelTimeToGoalArea(newarea, origin, botlibglobals.goalareanum, TFL_DEFAULT|TFL_ROCKETJUMP)); - /* - VectorCopy(origin, end); - end[2] += 5; - numareas = AAS_TraceAreas(origin, end, areas, NULL, 10); - AAS_TraceClientBBox(origin, end, PRESENCE_CROUCH, -1); - botimport.Print(PRT_MESSAGE, "num areas = %d, area = %d\n", numareas, areas[0]); - */ - /* - botlibglobals.goalareanum = newarea; - VectorCopy(parm2, botlibglobals.goalorigin); - botimport.Print(PRT_MESSAGE, "new goal %2.1f %2.1f %2.1f area %d\n", - origin[0], origin[1], origin[2], newarea); - */ - } //end if - //* - flood = LibVarGetValue("bot_flood"); - if (parm0 & 1) - { - if (flood) - { - AAS_ClearShownPolygons(); - AAS_ClearShownDebugLines(); - AAS_FloodAreas(parm2); - } - else - { - botlibglobals.goalareanum = newarea; - VectorCopy(parm2, botlibglobals.goalorigin); - botimport.Print(PRT_MESSAGE, "new goal %2.1f %2.1f %2.1f area %d\n", - origin[0], origin[1], origin[2], newarea); - } - } //end if*/ - if (flood) - return 0; -// if (parm0 & BUTTON_USE) -// { -// botlibglobals.runai = !botlibglobals.runai; -// if (botlibglobals.runai) botimport.Print(PRT_MESSAGE, "started AI\n"); -// else botimport.Print(PRT_MESSAGE, "stopped AI\n"); - //* / - /* - goal.areanum = botlibglobals.goalareanum; - reachnum = BotGetReachabilityToGoal(parm2, newarea, 1, - ms.avoidreach, ms.avoidreachtimes, - &goal, TFL_DEFAULT); - if (!reachnum) - { - botimport.Print(PRT_MESSAGE, "goal not reachable\n"); - } //end if - else - { - AAS_ReachabilityFromNum(reachnum, &reach); - AAS_ClearShownDebugLines(); - AAS_ShowArea(area, qtrue); - AAS_ShowArea(reach.areanum, qtrue); - AAS_DrawCross(reach.start, 6, LINECOLOR_BLUE); - AAS_DrawCross(reach.end, 6, LINECOLOR_RED); - // - if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_ELEVATOR) - { - ElevatorBottomCenter(&reach, bottomcenter); - AAS_DrawCross(bottomcenter, 10, LINECOLOR_GREEN); - } //end if - } //end else*/ -// botimport.Print(PRT_MESSAGE, "travel time to goal = %d\n", -// AAS_AreaTravelTimeToGoalArea(area, origin, botlibglobals.goalareanum, TFL_DEFAULT)); -// botimport.Print(PRT_MESSAGE, "test rj from 703 to 716\n"); -// AAS_Reachability_WeaponJump(703, 716); -// } //end if*/ - -/* face = AAS_AreaGroundFace(newarea, parm2); - if (face) - { - AAS_ShowFace(face - aasworld.faces); - } //end if*/ - /* - AAS_ClearShownDebugLines(); - AAS_ShowArea(newarea, parm0 & BUTTON_USE); - AAS_ShowReachableAreas(area); - */ - AAS_ClearShownPolygons(); - AAS_ClearShownDebugLines(); - AAS_ShowAreaPolygons(newarea, 1, parm0 & 4); - if (parm0 & 2) AAS_ShowReachableAreas(area); - else - { - static int lastgoalareanum, lastareanum; - static int avoidreach[MAX_AVOIDREACH]; - static float avoidreachtimes[MAX_AVOIDREACH]; - static int avoidreachtries[MAX_AVOIDREACH]; - int reachnum, resultFlags; - bot_goal_t goal; - aas_reachability_t reach; - - /* - goal.areanum = botlibglobals.goalareanum; - VectorCopy(botlibglobals.goalorigin, goal.origin); - reachnum = BotGetReachabilityToGoal(origin, newarea, - lastgoalareanum, lastareanum, - avoidreach, avoidreachtimes, avoidreachtries, - &goal, TFL_DEFAULT|TFL_FUNCBOB|TFL_ROCKETJUMP, TFL_DEFAULT|TFL_FUNCBOB|TFL_ROCKETJUMP, - NULL, 0, &resultFlags); - AAS_ReachabilityFromNum(reachnum, &reach); - AAS_ShowReachability(&reach); - */ - int curarea; - vec3_t curorigin; - - goal.areanum = botlibglobals.goalareanum; - VectorCopy(botlibglobals.goalorigin, goal.origin); - VectorCopy(origin, curorigin); - curarea = newarea; - for ( i = 0; i < 100; i++ ) { - if ( curarea == goal.areanum ) { - break; - } - reachnum = BotGetReachabilityToGoal(curorigin, curarea, - lastgoalareanum, lastareanum, - avoidreach, avoidreachtimes, avoidreachtries, - &goal, TFL_DEFAULT|TFL_FUNCBOB|TFL_ROCKETJUMP, TFL_DEFAULT|TFL_FUNCBOB|TFL_ROCKETJUMP, - NULL, 0, &resultFlags); - AAS_ReachabilityFromNum(reachnum, &reach); - AAS_ShowReachability(&reach); - VectorCopy(reach.end, origin); - lastareanum = curarea; - curarea = reach.areanum; - } - } //end else - VectorClear(forward); - //BotGapDistance(origin, forward, 0); - /* - if (parm0 & BUTTON_USE) - { - botimport.Print(PRT_MESSAGE, "test rj from 703 to 716\n"); - AAS_Reachability_WeaponJump(703, 716); - } //end if*/ - - AngleVectors(parm3, forward, right, NULL); - //get the eye 16 units to the right of the origin - VectorMA(parm2, 8, right, eye); - //get the eye 24 units up - eye[2] += 24; - //get the end point for the line to be traced - VectorMA(eye, 800, forward, end); - -// AAS_TestMovementPrediction(1, parm2, forward); -/* - //trace the line to find the hit point - trace = AAS_TraceClientBBox(eye, end, PRESENCE_NORMAL, 1); - if (!line[0]) line[0] = botimport.DebugLineCreate(); - botimport.DebugLineShow(line[0], eye, trace.endpos, LINECOLOR_BLUE); - // - AAS_ClearShownDebugLines(); - if (trace.ent) - { - ent = &aasworld.entities[trace.ent]; - AAS_ShowBoundingBox(ent->origin, ent->mins, ent->maxs); - } //end if -*/ - -/* - start_time = clock(); - for (i = 0; i < 2000; i++) - { - AAS_Trace2(eye, mins, maxs, end, 1, MASK_PLAYERSOLID); -// AAS_TraceClientBBox(eye, end, PRESENCE_NORMAL, 1); - } //end for - end_time = clock(); - botimport.Print(PRT_MESSAGE, "me %lu clocks, %lu CLOCKS_PER_SEC\n", end_time - start_time, CLOCKS_PER_SEC); - start_time = clock(); - for (i = 0; i < 2000; i++) - { - AAS_Trace(eye, mins, maxs, end, 1, MASK_PLAYERSOLID); - } //end for - end_time = clock(); - botimport.Print(PRT_MESSAGE, "id %lu clocks, %lu CLOCKS_PER_SEC\n", end_time - start_time, CLOCKS_PER_SEC); -*/ - - // TTimo: nested comments are BAD for gcc -Werror, use #if 0 instead.. -#if 0 - AAS_ClearShownDebugLines(); - //bsptrace = AAS_Trace(eye, NULL, NULL, end, 1, MASK_PLAYERSOLID); - bsptrace = AAS_Trace(eye, mins, maxs, end, 1, MASK_PLAYERSOLID); - if (!line[0]) line[0] = botimport.DebugLineCreate(); - botimport.DebugLineShow(line[0], eye, bsptrace.endpos, LINECOLOR_YELLOW); - if (bsptrace.fraction < 1.0) - { - face = AAS_TraceEndFace(&trace); - if (face) - { - AAS_ShowFace(face - aasworld.faces); - } //end if - - AAS_DrawPlaneCross(bsptrace.endpos, - bsptrace.plane.normal, - bsptrace.plane.dist + bsptrace.exp_dist, - bsptrace.plane.type, LINECOLOR_GREEN); - if (trace.ent) - { - ent = &aasworld.entities[trace.ent]; - AAS_ShowBoundingBox(ent->origin, ent->mins, ent->maxs); - } //end if - } //end if - //bsptrace = AAS_Trace2(eye, NULL, NULL, end, 1, MASK_PLAYERSOLID); - bsptrace = AAS_Trace2(eye, mins, maxs, end, 1, MASK_PLAYERSOLID); - botimport.DebugLineShow(line[1], eye, bsptrace.endpos, LINECOLOR_BLUE); - if (bsptrace.fraction < 1.0) - { - AAS_DrawPlaneCross(bsptrace.endpos, - bsptrace.plane.normal, - bsptrace.plane.dist,// + bsptrace.exp_dist, - bsptrace.plane.type, LINECOLOR_RED); - if (bsptrace.ent) - { - ent = &aasworld.entities[bsptrace.ent]; - AAS_ShowBoundingBox(ent->origin, ent->mins, ent->maxs); - } //end if - } //end if -#endif -#endif - return 0; -} //end of the function BotExportTest - - -/* -============ -Init_AAS_Export -============ -*/ -static void Init_AAS_Export( aas_export_t *aas ) { - //-------------------------------------------- - // be_aas_entity.c - //-------------------------------------------- - aas->AAS_EntityInfo = AAS_EntityInfo; - //-------------------------------------------- - // be_aas_main.c - //-------------------------------------------- - aas->AAS_Initialized = AAS_Initialized; - aas->AAS_PresenceTypeBoundingBox = AAS_PresenceTypeBoundingBox; - aas->AAS_Time = AAS_Time; - //-------------------------------------------- - // be_aas_sample.c - //-------------------------------------------- - aas->AAS_PointAreaNum = AAS_PointAreaNum; - aas->AAS_PointReachabilityAreaIndex = AAS_PointReachabilityAreaIndex; - aas->AAS_TraceAreas = AAS_TraceAreas; - aas->AAS_BBoxAreas = AAS_BBoxAreas; - aas->AAS_AreaInfo = AAS_AreaInfo; - //-------------------------------------------- - // be_aas_bspq3.c - //-------------------------------------------- - aas->AAS_PointContents = AAS_PointContents; - aas->AAS_NextBSPEntity = AAS_NextBSPEntity; - aas->AAS_ValueForBSPEpairKey = AAS_ValueForBSPEpairKey; - aas->AAS_VectorForBSPEpairKey = AAS_VectorForBSPEpairKey; - aas->AAS_FloatForBSPEpairKey = AAS_FloatForBSPEpairKey; - aas->AAS_IntForBSPEpairKey = AAS_IntForBSPEpairKey; - //-------------------------------------------- - // be_aas_reach.c - //-------------------------------------------- - aas->AAS_AreaReachability = AAS_AreaReachability; - //-------------------------------------------- - // be_aas_route.c - //-------------------------------------------- - aas->AAS_AreaTravelTimeToGoalArea = AAS_AreaTravelTimeToGoalArea; - aas->AAS_EnableRoutingArea = AAS_EnableRoutingArea; - aas->AAS_PredictRoute = AAS_PredictRoute; - //-------------------------------------------- - // be_aas_altroute.c - //-------------------------------------------- - aas->AAS_AlternativeRouteGoals = AAS_AlternativeRouteGoals; - //-------------------------------------------- - // be_aas_move.c - //-------------------------------------------- - aas->AAS_Swimming = AAS_Swimming; - aas->AAS_PredictClientMovement = AAS_PredictClientMovement; -} - - -/* -============ -Init_EA_Export -============ -*/ -static void Init_EA_Export( ea_export_t *ea ) { - //ClientCommand elementary actions - ea->EA_Command = EA_Command; - ea->EA_Say = EA_Say; - ea->EA_SayTeam = EA_SayTeam; - - ea->EA_Action = EA_Action; - ea->EA_Gesture = EA_Gesture; - ea->EA_Talk = EA_Talk; - ea->EA_Attack = EA_Attack; - ea->EA_Use = EA_Use; - ea->EA_Respawn = EA_Respawn; - ea->EA_Crouch = EA_Crouch; - ea->EA_MoveUp = EA_MoveUp; - ea->EA_MoveDown = EA_MoveDown; - ea->EA_MoveForward = EA_MoveForward; - ea->EA_MoveBack = EA_MoveBack; - ea->EA_MoveLeft = EA_MoveLeft; - ea->EA_MoveRight = EA_MoveRight; - - ea->EA_SelectWeapon = EA_SelectWeapon; - ea->EA_Jump = EA_Jump; - ea->EA_DelayedJump = EA_DelayedJump; - ea->EA_Move = EA_Move; - ea->EA_View = EA_View; - ea->EA_GetInput = EA_GetInput; - ea->EA_EndRegular = EA_EndRegular; - ea->EA_ResetInput = EA_ResetInput; -} - - -/* -============ -Init_AI_Export -============ -*/ -static void Init_AI_Export( ai_export_t *ai ) { - //----------------------------------- - // be_ai_char.h - //----------------------------------- - ai->BotLoadCharacter = BotLoadCharacter; - ai->BotFreeCharacter = BotFreeCharacter; - ai->Characteristic_Float = Characteristic_Float; - ai->Characteristic_BFloat = Characteristic_BFloat; - ai->Characteristic_Integer = Characteristic_Integer; - ai->Characteristic_BInteger = Characteristic_BInteger; - ai->Characteristic_String = Characteristic_String; - //----------------------------------- - // be_ai_chat.h - //----------------------------------- - ai->BotAllocChatState = BotAllocChatState; - ai->BotFreeChatState = BotFreeChatState; - ai->BotQueueConsoleMessage = BotQueueConsoleMessage; - ai->BotRemoveConsoleMessage = BotRemoveConsoleMessage; - ai->BotNextConsoleMessage = BotNextConsoleMessage; - ai->BotNumConsoleMessages = BotNumConsoleMessages; - ai->BotInitialChat = BotInitialChat; - ai->BotNumInitialChats = BotNumInitialChats; - ai->BotReplyChat = BotReplyChat; - ai->BotChatLength = BotChatLength; - ai->BotEnterChat = BotEnterChat; - ai->BotGetChatMessage = BotGetChatMessage; - ai->StringContains = StringContains; - ai->BotFindMatch = BotFindMatch; - ai->BotMatchVariable = BotMatchVariable; - ai->UnifyWhiteSpaces = UnifyWhiteSpaces; - ai->BotReplaceSynonyms = BotReplaceSynonyms; - ai->BotLoadChatFile = BotLoadChatFile; - ai->BotSetChatGender = BotSetChatGender; - ai->BotSetChatName = BotSetChatName; - //----------------------------------- - // be_ai_goal.h - //----------------------------------- - ai->BotResetGoalState = BotResetGoalState; - ai->BotResetAvoidGoals = BotResetAvoidGoals; - ai->BotRemoveFromAvoidGoals = BotRemoveFromAvoidGoals; - ai->BotPushGoal = BotPushGoal; - ai->BotPopGoal = BotPopGoal; - ai->BotEmptyGoalStack = BotEmptyGoalStack; - ai->BotDumpAvoidGoals = BotDumpAvoidGoals; - ai->BotDumpGoalStack = BotDumpGoalStack; - ai->BotGoalName = BotGoalName; - ai->BotGetTopGoal = BotGetTopGoal; - ai->BotGetSecondGoal = BotGetSecondGoal; - ai->BotChooseLTGItem = BotChooseLTGItem; - ai->BotChooseNBGItem = BotChooseNBGItem; - ai->BotTouchingGoal = BotTouchingGoal; - ai->BotItemGoalInVisButNotVisible = BotItemGoalInVisButNotVisible; - ai->BotGetLevelItemGoal = BotGetLevelItemGoal; - ai->BotGetNextCampSpotGoal = BotGetNextCampSpotGoal; - ai->BotGetMapLocationGoal = BotGetMapLocationGoal; - ai->BotAvoidGoalTime = BotAvoidGoalTime; - ai->BotSetAvoidGoalTime = BotSetAvoidGoalTime; - ai->BotInitLevelItems = BotInitLevelItems; - ai->BotUpdateEntityItems = BotUpdateEntityItems; - ai->BotLoadItemWeights = BotLoadItemWeights; - ai->BotFreeItemWeights = BotFreeItemWeights; - ai->BotInterbreedGoalFuzzyLogic = BotInterbreedGoalFuzzyLogic; - ai->BotSaveGoalFuzzyLogic = BotSaveGoalFuzzyLogic; - ai->BotMutateGoalFuzzyLogic = BotMutateGoalFuzzyLogic; - ai->BotAllocGoalState = BotAllocGoalState; - ai->BotFreeGoalState = BotFreeGoalState; - //----------------------------------- - // be_ai_move.h - //----------------------------------- - ai->BotResetMoveState = BotResetMoveState; - ai->BotMoveToGoal = BotMoveToGoal; - ai->BotMoveInDirection = BotMoveInDirection; - ai->BotResetAvoidReach = BotResetAvoidReach; - ai->BotResetLastAvoidReach = BotResetLastAvoidReach; - ai->BotReachabilityArea = BotReachabilityArea; - ai->BotMovementViewTarget = BotMovementViewTarget; - ai->BotPredictVisiblePosition = BotPredictVisiblePosition; - ai->BotAllocMoveState = BotAllocMoveState; - ai->BotFreeMoveState = BotFreeMoveState; - ai->BotInitMoveState = BotInitMoveState; - ai->BotAddAvoidSpot = BotAddAvoidSpot; - //----------------------------------- - // be_ai_weap.h - //----------------------------------- - ai->BotChooseBestFightWeapon = BotChooseBestFightWeapon; - ai->BotGetWeaponInfo = BotGetWeaponInfo; - ai->BotLoadWeaponWeights = BotLoadWeaponWeights; - ai->BotAllocWeaponState = BotAllocWeaponState; - ai->BotFreeWeaponState = BotFreeWeaponState; - ai->BotResetWeaponState = BotResetWeaponState; - //----------------------------------- - // be_ai_gen.h - //----------------------------------- - ai->GeneticParentsAndChildSelection = GeneticParentsAndChildSelection; -} - - -/* -============ -GetBotLibAPI -============ -*/ -botlib_export_t *GetBotLibAPI(int apiVersion, botlib_import_t *import) { - assert(import); // bk001129 - this wasn't set for baseq3/ - botimport = *import; - assert(botimport.Print); // bk001129 - pars pro toto - - Com_Memset( &be_botlib_export, 0, sizeof( be_botlib_export ) ); - - if ( apiVersion != BOTLIB_API_VERSION ) { - botimport.Print( PRT_ERROR, "Mismatched BOTLIB_API_VERSION: expected %i, got %i\n", BOTLIB_API_VERSION, apiVersion ); - return NULL; - } - - Init_AAS_Export(&be_botlib_export.aas); - Init_EA_Export(&be_botlib_export.ea); - Init_AI_Export(&be_botlib_export.ai); - - be_botlib_export.BotLibSetup = Export_BotLibSetup; - be_botlib_export.BotLibShutdown = Export_BotLibShutdown; - be_botlib_export.BotLibVarSet = Export_BotLibVarSet; - be_botlib_export.BotLibVarGet = Export_BotLibVarGet; - - be_botlib_export.PC_AddGlobalDefine = PC_AddGlobalDefine; - be_botlib_export.PC_LoadSourceHandle = PC_LoadSourceHandle; - be_botlib_export.PC_FreeSourceHandle = PC_FreeSourceHandle; - be_botlib_export.PC_ReadTokenHandle = PC_ReadTokenHandle; - be_botlib_export.PC_SourceFileAndLine = PC_SourceFileAndLine; - - be_botlib_export.BotLibStartFrame = Export_BotLibStartFrame; - be_botlib_export.BotLibLoadMap = Export_BotLibLoadMap; - be_botlib_export.BotLibUpdateEntity = Export_BotLibUpdateEntity; - be_botlib_export.Test = BotExportTest; - - return &be_botlib_export; -} diff --git a/src/botlib/be_interface.h b/src/botlib/be_interface.h deleted file mode 100644 index 8210667d..00000000 --- a/src/botlib/be_interface.h +++ /dev/null @@ -1,58 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_interface.h - * - * desc: botlib interface - * - * $Archive: /source/code/botlib/be_interface.h $ - * - *****************************************************************************/ - -//#define DEBUG //debug code -#define RANDOMIZE //randomize bot behaviour - -//FIXME: get rid of this global structure -typedef struct botlib_globals_s -{ - int botlibsetup; //true when the bot library has been setup - int maxentities; //maximum number of entities - int maxclients; //maximum number of clients - float time; //the global time -#ifdef DEBUG - qboolean debug; //true if debug is on - int goalareanum; - vec3_t goalorigin; - int runai; -#endif -} botlib_globals_t; - - -extern botlib_globals_t botlibglobals; -extern botlib_import_t botimport; -extern int bot_developer; //true if developer is on - -// -int Sys_MilliSeconds(void); - diff --git a/src/botlib/botlib.h b/src/botlib/botlib.h deleted file mode 100644 index 6c5147df..00000000 --- a/src/botlib/botlib.h +++ /dev/null @@ -1,517 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// -/***************************************************************************** - * name: botlib.h - * - * desc: bot AI library - * - * $Archive: /source/code/game/botai.h $ - * - *****************************************************************************/ - -#define BOTLIB_API_VERSION 2 - -struct aas_clientmove_s; -struct aas_entityinfo_s; -struct aas_areainfo_s; -struct aas_altroutegoal_s; -struct aas_predictroute_s; -struct bot_consolemessage_s; -struct bot_match_s; -struct bot_goal_s; -struct bot_moveresult_s; -struct bot_initmove_s; -struct weaponinfo_s; - -#define BOTFILESBASEFOLDER "botfiles" -//debug line colors -#define LINECOLOR_NONE -1 -#define LINECOLOR_RED 1//0xf2f2f0f0L -#define LINECOLOR_GREEN 2//0xd0d1d2d3L -#define LINECOLOR_BLUE 3//0xf3f3f1f1L -#define LINECOLOR_YELLOW 4//0xdcdddedfL -#define LINECOLOR_ORANGE 5//0xe0e1e2e3L - -//Print types -#define PRT_MESSAGE 1 -#define PRT_WARNING 2 -#define PRT_ERROR 3 -#define PRT_FATAL 4 -#define PRT_EXIT 5 - -//console message types -#define CMS_NORMAL 0 -#define CMS_CHAT 1 - -//botlib error codes -#define BLERR_NOERROR 0 //no error -#define BLERR_LIBRARYNOTSETUP 1 //library not setup -#define BLERR_INVALIDENTITYNUMBER 2 //invalid entity number -#define BLERR_NOAASFILE 3 //no AAS file available -#define BLERR_CANNOTOPENAASFILE 4 //cannot open AAS file -#define BLERR_WRONGAASFILEID 5 //incorrect AAS file id -#define BLERR_WRONGAASFILEVERSION 6 //incorrect AAS file version -#define BLERR_CANNOTREADAASLUMP 7 //cannot read AAS file lump -#define BLERR_CANNOTLOADICHAT 8 //cannot load initial chats -#define BLERR_CANNOTLOADITEMWEIGHTS 9 //cannot load item weights -#define BLERR_CANNOTLOADITEMCONFIG 10 //cannot load item config -#define BLERR_CANNOTLOADWEAPONWEIGHTS 11 //cannot load weapon weights -#define BLERR_CANNOTLOADWEAPONCONFIG 12 //cannot load weapon config - -//action flags -#define ACTION_ATTACK 0x0000001 -#define ACTION_USE 0x0000002 -#define ACTION_RESPAWN 0x0000008 -#define ACTION_JUMP 0x0000010 -#define ACTION_MOVEUP 0x0000020 -#define ACTION_CROUCH 0x0000080 -#define ACTION_MOVEDOWN 0x0000100 -#define ACTION_MOVEFORWARD 0x0000200 -#define ACTION_MOVEBACK 0x0000800 -#define ACTION_MOVELEFT 0x0001000 -#define ACTION_MOVERIGHT 0x0002000 -#define ACTION_DELAYEDJUMP 0x0008000 -#define ACTION_TALK 0x0010000 -#define ACTION_GESTURE 0x0020000 -#define ACTION_WALK 0x0080000 -#define ACTION_AFFIRMATIVE 0x0100000 -#define ACTION_NEGATIVE 0x0200000 -#define ACTION_GETFLAG 0x0800000 -#define ACTION_GUARDBASE 0x1000000 -#define ACTION_PATROL 0x2000000 -#define ACTION_FOLLOWME 0x8000000 - -//the bot input, will be converted to an usercmd_t -typedef struct bot_input_s -{ - float thinktime; //time since last output (in seconds) - vec3_t dir; //movement direction - float speed; //speed in the range [0, 400] - vec3_t viewangles; //the view angles - int actionflags; //one of the ACTION_? flags - int weapon; //weapon to use -} bot_input_t; - -#ifndef BSPTRACE - -#define BSPTRACE - -//bsp_trace_t hit surface -typedef struct bsp_surface_s -{ - char name[16]; - int flags; - int value; -} bsp_surface_t; - -//remove the bsp_trace_s structure definition l8r on -//a trace is returned when a box is swept through the world -typedef struct bsp_trace_s -{ - qboolean allsolid; // if true, plane is not valid - qboolean startsolid; // if true, the initial point was in a solid area - float fraction; // time completed, 1.0 = didn't hit anything - vec3_t endpos; // final position - cplane_t plane; // surface normal at impact - float exp_dist; // expanded plane distance - int sidenum; // number of the brush side hit - bsp_surface_t surface; // the hit point surface - int contents; // contents on other side of surface hit - int ent; // number of entity hit -} bsp_trace_t; - -#endif // BSPTRACE - -//entity state -typedef struct bot_entitystate_s -{ - int type; // entity type - int flags; // entity flags - vec3_t origin; // origin of the entity - vec3_t angles; // angles of the model - vec3_t old_origin; // for lerping - vec3_t mins; // bounding box minimums - vec3_t maxs; // bounding box maximums - int groundent; // ground entity - int solid; // solid type - int modelindex; // model used - int modelindex2; // weapons, CTF flags, etc - int frame; // model frame number - int event; // impulse events -- muzzle flashes, footsteps, etc - int eventParm; // even parameter - int powerups; // bit flags - int weapon; // determines weapon and flash model, etc - int legsAnim; // mask off ANIM_TOGGLEBIT - int torsoAnim; // mask off ANIM_TOGGLEBIT -} bot_entitystate_t; - -//bot AI library exported functions -typedef struct botlib_import_s -{ - //print messages from the bot library - void (QDECL *Print)(int type, char *fmt, ...); - //trace a bbox through the world - void (*Trace)(bsp_trace_t *trace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int passent, int contentmask); - //trace a bbox against a specific entity - void (*EntityTrace)(bsp_trace_t *trace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int entnum, int contentmask); - //retrieve the contents at the given point - int (*PointContents)(vec3_t point); - //check if the point is in potential visible sight - int (*inPVS)(vec3_t p1, vec3_t p2); - //retrieve the BSP entity data lump - char *(*BSPEntityData)(void); - // - void (*BSPModelMinsMaxsOrigin)(int modelnum, vec3_t angles, vec3_t mins, vec3_t maxs, vec3_t origin); - //send a bot client command - void (*BotClientCommand)(int client, char *command); - //memory allocation - void *(*GetMemory)(int size); // allocate from Zone - void (*FreeMemory)(void *ptr); // free memory from Zone - int (*AvailableMemory)(void); // available Zone memory - void *(*HunkAlloc)(int size); // allocate from hunk - //file system access - int (*FS_FOpenFile)( const char *qpath, fileHandle_t *file, fsMode_t mode ); - int (*FS_Read)( void *buffer, int len, fileHandle_t f ); - int (*FS_Write)( const void *buffer, int len, fileHandle_t f ); - void (*FS_FCloseFile)( fileHandle_t f ); - int (*FS_Seek)( fileHandle_t f, long offset, int origin ); - //debug visualisation stuff - int (*DebugLineCreate)(void); - void (*DebugLineDelete)(int line); - void (*DebugLineShow)(int line, vec3_t start, vec3_t end, int color); - // - int (*DebugPolygonCreate)(int color, int numPoints, vec3_t *points); - void (*DebugPolygonDelete)(int id); -} botlib_import_t; - -typedef struct aas_export_s -{ - //----------------------------------- - // be_aas_entity.h - //----------------------------------- - void (*AAS_EntityInfo)(int entnum, struct aas_entityinfo_s *info); - //----------------------------------- - // be_aas_main.h - //----------------------------------- - int (*AAS_Initialized)(void); - void (*AAS_PresenceTypeBoundingBox)(int presencetype, vec3_t mins, vec3_t maxs); - float (*AAS_Time)(void); - //-------------------------------------------- - // be_aas_sample.c - //-------------------------------------------- - int (*AAS_PointAreaNum)(vec3_t point); - int (*AAS_PointReachabilityAreaIndex)( vec3_t point ); - int (*AAS_TraceAreas)(vec3_t start, vec3_t end, int *areas, vec3_t *points, int maxareas); - int (*AAS_BBoxAreas)(vec3_t absmins, vec3_t absmaxs, int *areas, int maxareas); - int (*AAS_AreaInfo)( int areanum, struct aas_areainfo_s *info ); - //-------------------------------------------- - // be_aas_bspq3.c - //-------------------------------------------- - int (*AAS_PointContents)(vec3_t point); - int (*AAS_NextBSPEntity)(int ent); - int (*AAS_ValueForBSPEpairKey)(int ent, char *key, char *value, int size); - int (*AAS_VectorForBSPEpairKey)(int ent, char *key, vec3_t v); - int (*AAS_FloatForBSPEpairKey)(int ent, char *key, float *value); - int (*AAS_IntForBSPEpairKey)(int ent, char *key, int *value); - //-------------------------------------------- - // be_aas_reach.c - //-------------------------------------------- - int (*AAS_AreaReachability)(int areanum); - //-------------------------------------------- - // be_aas_route.c - //-------------------------------------------- - int (*AAS_AreaTravelTimeToGoalArea)(int areanum, vec3_t origin, int goalareanum, int travelflags); - int (*AAS_EnableRoutingArea)(int areanum, int enable); - int (*AAS_PredictRoute)(struct aas_predictroute_s *route, int areanum, vec3_t origin, - int goalareanum, int travelflags, int maxareas, int maxtime, - int stopevent, int stopcontents, int stoptfl, int stopareanum); - //-------------------------------------------- - // be_aas_altroute.c - //-------------------------------------------- - int (*AAS_AlternativeRouteGoals)(vec3_t start, int startareanum, vec3_t goal, int goalareanum, int travelflags, - struct aas_altroutegoal_s *altroutegoals, int maxaltroutegoals, - int type); - //-------------------------------------------- - // be_aas_move.c - //-------------------------------------------- - int (*AAS_Swimming)(vec3_t origin); - int (*AAS_PredictClientMovement)(struct aas_clientmove_s *move, - int entnum, vec3_t origin, - int presencetype, int onground, - vec3_t velocity, vec3_t cmdmove, - int cmdframes, - int maxframes, float frametime, - int stopevent, int stopareanum, int visualize); -} aas_export_t; - -typedef struct ea_export_s -{ - //ClientCommand elementary actions - void (*EA_Command)(int client, char *command ); - void (*EA_Say)(int client, char *str); - void (*EA_SayTeam)(int client, char *str); - // - void (*EA_Action)(int client, int action); - void (*EA_Gesture)(int client); - void (*EA_Talk)(int client); - void (*EA_Attack)(int client); - void (*EA_Use)(int client); - void (*EA_Respawn)(int client); - void (*EA_MoveUp)(int client); - void (*EA_MoveDown)(int client); - void (*EA_MoveForward)(int client); - void (*EA_MoveBack)(int client); - void (*EA_MoveLeft)(int client); - void (*EA_MoveRight)(int client); - void (*EA_Crouch)(int client); - - void (*EA_SelectWeapon)(int client, int weapon); - void (*EA_Jump)(int client); - void (*EA_DelayedJump)(int client); - void (*EA_Move)(int client, vec3_t dir, float speed); - void (*EA_View)(int client, vec3_t viewangles); - //send regular input to the server - void (*EA_EndRegular)(int client, float thinktime); - void (*EA_GetInput)(int client, float thinktime, bot_input_t *input); - void (*EA_ResetInput)(int client); -} ea_export_t; - -typedef struct ai_export_s -{ - //----------------------------------- - // be_ai_char.h - //----------------------------------- - int (*BotLoadCharacter)(char *charfile, float skill); - void (*BotFreeCharacter)(int character); - float (*Characteristic_Float)(int character, int index); - float (*Characteristic_BFloat)(int character, int index, float min, float max); - int (*Characteristic_Integer)(int character, int index); - int (*Characteristic_BInteger)(int character, int index, int min, int max); - void (*Characteristic_String)(int character, int index, char *buf, int size); - //----------------------------------- - // be_ai_chat.h - //----------------------------------- - int (*BotAllocChatState)(void); - void (*BotFreeChatState)(int handle); - void (*BotQueueConsoleMessage)(int chatstate, int type, char *message); - void (*BotRemoveConsoleMessage)(int chatstate, int handle); - int (*BotNextConsoleMessage)(int chatstate, struct bot_consolemessage_s *cm); - int (*BotNumConsoleMessages)(int chatstate); - void (*BotInitialChat)(int chatstate, char *type, int mcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7); - int (*BotNumInitialChats)(int chatstate, char *type); - int (*BotReplyChat)(int chatstate, char *message, int mcontext, int vcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7); - int (*BotChatLength)(int chatstate); - void (*BotEnterChat)(int chatstate, int client, int sendto); - void (*BotGetChatMessage)(int chatstate, char *buf, int size); - int (*StringContains)(char *str1, char *str2, int casesensitive); - int (*BotFindMatch)(char *str, struct bot_match_s *match, unsigned long int context); - void (*BotMatchVariable)(struct bot_match_s *match, int variable, char *buf, int size); - void (*UnifyWhiteSpaces)(char *string); - void (*BotReplaceSynonyms)(char *string, unsigned long int context); - int (*BotLoadChatFile)(int chatstate, char *chatfile, char *chatname); - void (*BotSetChatGender)(int chatstate, int gender); - void (*BotSetChatName)(int chatstate, char *name, int client); - //----------------------------------- - // be_ai_goal.h - //----------------------------------- - void (*BotResetGoalState)(int goalstate); - void (*BotResetAvoidGoals)(int goalstate); - void (*BotRemoveFromAvoidGoals)(int goalstate, int number); - void (*BotPushGoal)(int goalstate, struct bot_goal_s *goal); - void (*BotPopGoal)(int goalstate); - void (*BotEmptyGoalStack)(int goalstate); - void (*BotDumpAvoidGoals)(int goalstate); - void (*BotDumpGoalStack)(int goalstate); - void (*BotGoalName)(int number, char *name, int size); - int (*BotGetTopGoal)(int goalstate, struct bot_goal_s *goal); - int (*BotGetSecondGoal)(int goalstate, struct bot_goal_s *goal); - int (*BotChooseLTGItem)(int goalstate, vec3_t origin, int *inventory, int travelflags); - int (*BotChooseNBGItem)(int goalstate, vec3_t origin, int *inventory, int travelflags, - struct bot_goal_s *ltg, float maxtime); - int (*BotTouchingGoal)(vec3_t origin, struct bot_goal_s *goal); - int (*BotItemGoalInVisButNotVisible)(int viewer, vec3_t eye, vec3_t viewangles, struct bot_goal_s *goal); - int (*BotGetLevelItemGoal)(int index, char *classname, struct bot_goal_s *goal); - int (*BotGetNextCampSpotGoal)(int num, struct bot_goal_s *goal); - int (*BotGetMapLocationGoal)(char *name, struct bot_goal_s *goal); - float (*BotAvoidGoalTime)(int goalstate, int number); - void (*BotSetAvoidGoalTime)(int goalstate, int number, float avoidtime); - void (*BotInitLevelItems)(void); - void (*BotUpdateEntityItems)(void); - int (*BotLoadItemWeights)(int goalstate, char *filename); - void (*BotFreeItemWeights)(int goalstate); - void (*BotInterbreedGoalFuzzyLogic)(int parent1, int parent2, int child); - void (*BotSaveGoalFuzzyLogic)(int goalstate, char *filename); - void (*BotMutateGoalFuzzyLogic)(int goalstate, float range); - int (*BotAllocGoalState)(int client); - void (*BotFreeGoalState)(int handle); - //----------------------------------- - // be_ai_move.h - //----------------------------------- - void (*BotResetMoveState)(int movestate); - void (*BotMoveToGoal)(struct bot_moveresult_s *result, int movestate, struct bot_goal_s *goal, int travelflags); - int (*BotMoveInDirection)(int movestate, vec3_t dir, float speed, int type); - void (*BotResetAvoidReach)(int movestate); - void (*BotResetLastAvoidReach)(int movestate); - int (*BotReachabilityArea)(vec3_t origin, int testground); - int (*BotMovementViewTarget)(int movestate, struct bot_goal_s *goal, int travelflags, float lookahead, vec3_t target); - int (*BotPredictVisiblePosition)(vec3_t origin, int areanum, struct bot_goal_s *goal, int travelflags, vec3_t target); - int (*BotAllocMoveState)(void); - void (*BotFreeMoveState)(int handle); - void (*BotInitMoveState)(int handle, struct bot_initmove_s *initmove); - void (*BotAddAvoidSpot)(int movestate, vec3_t origin, float radius, int type); - //----------------------------------- - // be_ai_weap.h - //----------------------------------- - int (*BotChooseBestFightWeapon)(int weaponstate, int *inventory); - void (*BotGetWeaponInfo)(int weaponstate, int weapon, struct weaponinfo_s *weaponinfo); - int (*BotLoadWeaponWeights)(int weaponstate, char *filename); - int (*BotAllocWeaponState)(void); - void (*BotFreeWeaponState)(int weaponstate); - void (*BotResetWeaponState)(int weaponstate); - //----------------------------------- - // be_ai_gen.h - //----------------------------------- - int (*GeneticParentsAndChildSelection)(int numranks, float *ranks, int *parent1, int *parent2, int *child); -} ai_export_t; - -//bot AI library imported functions -typedef struct botlib_export_s -{ - //Area Awareness System functions - aas_export_t aas; - //Elementary Action functions - ea_export_t ea; - //AI functions - ai_export_t ai; - //setup the bot library, returns BLERR_ - int (*BotLibSetup)(void); - //shutdown the bot library, returns BLERR_ - int (*BotLibShutdown)(void); - //sets a library variable returns BLERR_ - int (*BotLibVarSet)(char *var_name, char *value); - //gets a library variable returns BLERR_ - int (*BotLibVarGet)(char *var_name, char *value, int size); - - //sets a C-like define returns BLERR_ - int (*PC_AddGlobalDefine)(char *string); - int (*PC_LoadSourceHandle)(const char *filename); - int (*PC_FreeSourceHandle)(int handle); - int (*PC_ReadTokenHandle)(int handle, pc_token_t *pc_token); - int (*PC_SourceFileAndLine)(int handle, char *filename, int *line); - - //start a frame in the bot library - int (*BotLibStartFrame)(float time); - //load a new map in the bot library - int (*BotLibLoadMap)(const char *mapname); - //entity updates - int (*BotLibUpdateEntity)(int ent, bot_entitystate_t *state); - //just for testing - int (*Test)(int parm0, char *parm1, vec3_t parm2, vec3_t parm3); -} botlib_export_t; - -//linking of bot library -botlib_export_t *GetBotLibAPI( int apiVersion, botlib_import_t *import ); - -/* Library variables: - -name: default: module(s): description: - -"basedir" "" l_utils.c base directory -"gamedir" "" l_utils.c game directory -"cddir" "" l_utils.c CD directory - -"log" "0" l_log.c enable/disable creating a log file -"maxclients" "4" be_interface.c maximum number of clients -"maxentities" "1024" be_interface.c maximum number of entities -"bot_developer" "0" be_interface.c bot developer mode - -"phys_friction" "6" be_aas_move.c ground friction -"phys_stopspeed" "100" be_aas_move.c stop speed -"phys_gravity" "800" be_aas_move.c gravity value -"phys_waterfriction" "1" be_aas_move.c water friction -"phys_watergravity" "400" be_aas_move.c gravity in water -"phys_maxvelocity" "320" be_aas_move.c maximum velocity -"phys_maxwalkvelocity" "320" be_aas_move.c maximum walk velocity -"phys_maxcrouchvelocity" "100" be_aas_move.c maximum crouch velocity -"phys_maxswimvelocity" "150" be_aas_move.c maximum swim velocity -"phys_walkaccelerate" "10" be_aas_move.c walk acceleration -"phys_airaccelerate" "1" be_aas_move.c air acceleration -"phys_swimaccelerate" "4" be_aas_move.c swim acceleration -"phys_maxstep" "18" be_aas_move.c maximum step height -"phys_maxsteepness" "0.7" be_aas_move.c maximum floor steepness -"phys_maxbarrier" "32" be_aas_move.c maximum barrier height -"phys_maxwaterjump" "19" be_aas_move.c maximum waterjump height -"phys_jumpvel" "270" be_aas_move.c jump z velocity -"phys_falldelta5" "40" be_aas_move.c -"phys_falldelta10" "60" be_aas_move.c -"rs_waterjump" "400" be_aas_move.c -"rs_teleport" "50" be_aas_move.c -"rs_barrierjump" "100" be_aas_move.c -"rs_startcrouch" "300" be_aas_move.c -"rs_startgrapple" "500" be_aas_move.c -"rs_startwalkoffledge" "70" be_aas_move.c -"rs_startjump" "300" be_aas_move.c -"rs_rocketjump" "500" be_aas_move.c -"rs_bfgjump" "500" be_aas_move.c -"rs_jumppad" "250" be_aas_move.c -"rs_aircontrolledjumppad" "300" be_aas_move.c -"rs_funcbob" "300" be_aas_move.c -"rs_startelevator" "50" be_aas_move.c -"rs_falldamage5" "300" be_aas_move.c -"rs_falldamage10" "500" be_aas_move.c -"rs_maxjumpfallheight" "450" be_aas_move.c - -"max_aaslinks" "4096" be_aas_sample.c maximum links in the AAS -"max_routingcache" "4096" be_aas_route.c maximum routing cache size in KB -"forceclustering" "0" be_aas_main.c force recalculation of clusters -"forcereachability" "0" be_aas_main.c force recalculation of reachabilities -"forcewrite" "0" be_aas_main.c force writing of aas file -"aasoptimize" "0" be_aas_main.c enable aas optimization -"sv_mapChecksum" "0" be_aas_main.c BSP file checksum -"bot_visualizejumppads" "0" be_aas_reach.c visualize jump pads - -"bot_reloadcharacters" "0" - reload bot character files -"ai_gametype" "0" be_ai_goal.c game type -"droppedweight" "1000" be_ai_goal.c additional dropped item weight -"weapindex_rocketlauncher" "5" be_ai_move.c rl weapon index for rocket jumping -"weapindex_bfg10k" "9" be_ai_move.c bfg weapon index for bfg jumping -"weapindex_grapple" "10" be_ai_move.c grapple weapon index for grappling -"entitytypemissile" "3" be_ai_move.c ET_MISSILE -"offhandgrapple" "0" be_ai_move.c enable off hand grapple hook -"cmd_grappleon" "grappleon" be_ai_move.c command to activate off hand grapple -"cmd_grappleoff" "grappleoff" be_ai_move.c command to deactivate off hand grapple -"itemconfig" "items.c" be_ai_goal.c item configuration file -"weaponconfig" "weapons.c" be_ai_weap.c weapon configuration file -"synfile" "syn.c" be_ai_chat.c file with synonyms -"rndfile" "rnd.c" be_ai_chat.c file with random strings -"matchfile" "match.c" be_ai_chat.c file with match strings -"nochat" "0" be_ai_chat.c disable chats -"max_messages" "1024" be_ai_chat.c console message heap size -"max_weaponinfo" "32" be_ai_weap.c maximum number of weapon info -"max_projectileinfo" "32" be_ai_weap.c maximum number of projectile info -"max_iteminfo" "256" be_ai_goal.c maximum number of item info -"max_levelitems" "256" be_ai_goal.c maximum number of level items - -*/ - diff --git a/src/botlib/l_crc.c b/src/botlib/l_crc.c deleted file mode 100644 index 0903fa22..00000000 --- a/src/botlib/l_crc.c +++ /dev/null @@ -1,152 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: l_crc.c - * - * desc: CRC calculation - * - * $Archive: /MissionPack/CODE/botlib/l_crc.c $ - * - *****************************************************************************/ - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> - -#include "../qcommon/q_shared.h" -#include "botlib.h" -#include "be_interface.h" //for botimport.Print - - -// FIXME: byte swap? - -// this is a 16 bit, non-reflected CRC using the polynomial 0x1021 -// and the initial and final xor values shown below... in other words, the -// CCITT standard CRC used by XMODEM - -#define CRC_INIT_VALUE 0xffff -#define CRC_XOR_VALUE 0x0000 - -unsigned short crctable[257] = -{ - 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, - 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, - 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, - 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, - 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, - 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, - 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, - 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, - 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, - 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, - 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, - 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, - 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, - 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, - 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, - 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, - 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, - 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, - 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, - 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, - 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, - 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, - 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, - 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, - 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, - 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, - 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, - 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, - 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, - 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, - 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, - 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 -}; - -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void CRC_Init(unsigned short *crcvalue) -{ - *crcvalue = CRC_INIT_VALUE; -} //end of the function CRC_Init -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void CRC_ProcessByte(unsigned short *crcvalue, byte data) -{ - *crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data]; -} //end of the function CRC_ProcessByte -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -unsigned short CRC_Value(unsigned short crcvalue) -{ - return crcvalue ^ CRC_XOR_VALUE; -} //end of the function CRC_Value -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -unsigned short CRC_ProcessString(unsigned char *data, int length) -{ - unsigned short crcvalue; - int i, ind; - - CRC_Init(&crcvalue); - - for (i = 0; i < length; i++) - { - ind = (crcvalue >> 8) ^ data[i]; - if (ind < 0 || ind > 256) ind = 0; - crcvalue = (crcvalue << 8) ^ crctable[ind]; - } //end for - return CRC_Value(crcvalue); -} //end of the function CRC_ProcessString -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void CRC_ContinueProcessString(unsigned short *crc, char *data, int length) -{ - int i; - - for (i = 0; i < length; i++) - { - *crc = (*crc << 8) ^ crctable[(*crc >> 8) ^ data[i]]; - } //end for -} //end of the function CRC_ProcessString diff --git a/src/botlib/l_crc.h b/src/botlib/l_crc.h deleted file mode 100644 index d5eb284f..00000000 --- a/src/botlib/l_crc.h +++ /dev/null @@ -1,30 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -typedef unsigned short crc_t; - -void CRC_Init(unsigned short *crcvalue); -void CRC_ProcessByte(unsigned short *crcvalue, byte data); -unsigned short CRC_Value(unsigned short crcvalue); -unsigned short CRC_ProcessString(unsigned char *data, int length); -void CRC_ContinueProcessString(unsigned short *crc, char *data, int length); diff --git a/src/botlib/l_libvar.c b/src/botlib/l_libvar.c deleted file mode 100644 index df2ca092..00000000 --- a/src/botlib/l_libvar.c +++ /dev/null @@ -1,295 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: l_libvar.c - * - * desc: bot library variables - * - * $Archive: /MissionPack/code/botlib/l_libvar.c $ - * - *****************************************************************************/ - -#include "../qcommon/q_shared.h" -#include "l_memory.h" -#include "l_libvar.h" - -//list with library variables -libvar_t *libvarlist; - -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -float LibVarStringValue(char *string) -{ - int dotfound = 0; - float value = 0; - - while(*string) - { - if (*string < '0' || *string > '9') - { - if (dotfound || *string != '.') - { - return 0; - } //end if - else - { - dotfound = 10; - string++; - } //end if - } //end if - if (dotfound) - { - value = value + (float) (*string - '0') / (float) dotfound; - dotfound *= 10; - } //end if - else - { - value = value * 10.0 + (float) (*string - '0'); - } //end else - string++; - } //end while - return value; -} //end of the function LibVarStringValue -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -libvar_t *LibVarAlloc(char *var_name) -{ - libvar_t *v; - - v = (libvar_t *) GetMemory(sizeof(libvar_t) + strlen(var_name) + 1); - Com_Memset(v, 0, sizeof(libvar_t)); - v->name = (char *) v + sizeof(libvar_t); - strcpy(v->name, var_name); - //add the variable in the list - v->next = libvarlist; - libvarlist = v; - return v; -} //end of the function LibVarAlloc -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void LibVarDeAlloc(libvar_t *v) -{ - if (v->string) FreeMemory(v->string); - FreeMemory(v); -} //end of the function LibVarDeAlloc -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void LibVarDeAllocAll(void) -{ - libvar_t *v; - - for (v = libvarlist; v; v = libvarlist) - { - libvarlist = libvarlist->next; - LibVarDeAlloc(v); - } //end for - libvarlist = NULL; -} //end of the function LibVarDeAllocAll -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -libvar_t *LibVarGet(char *var_name) -{ - libvar_t *v; - - for (v = libvarlist; v; v = v->next) - { - if (!Q_stricmp(v->name, var_name)) - { - return v; - } //end if - } //end for - return NULL; -} //end of the function LibVarGet -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -char *LibVarGetString(char *var_name) -{ - libvar_t *v; - - v = LibVarGet(var_name); - if (v) - { - return v->string; - } //end if - else - { - return ""; - } //end else -} //end of the function LibVarGetString -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -float LibVarGetValue(char *var_name) -{ - libvar_t *v; - - v = LibVarGet(var_name); - if (v) - { - return v->value; - } //end if - else - { - return 0; - } //end else -} //end of the function LibVarGetValue -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -libvar_t *LibVar(char *var_name, char *value) -{ - libvar_t *v; - v = LibVarGet(var_name); - if (v) return v; - //create new variable - v = LibVarAlloc(var_name); - //variable string - v->string = (char *) GetMemory(strlen(value) + 1); - strcpy(v->string, value); - //the value - v->value = LibVarStringValue(v->string); - //variable is modified - v->modified = qtrue; - // - return v; -} //end of the function LibVar -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -char *LibVarString(char *var_name, char *value) -{ - libvar_t *v; - - v = LibVar(var_name, value); - return v->string; -} //end of the function LibVarString -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -float LibVarValue(char *var_name, char *value) -{ - libvar_t *v; - - v = LibVar(var_name, value); - return v->value; -} //end of the function LibVarValue -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void LibVarSet(char *var_name, char *value) -{ - libvar_t *v; - - v = LibVarGet(var_name); - if (v) - { - FreeMemory(v->string); - } //end if - else - { - v = LibVarAlloc(var_name); - } //end else - //variable string - v->string = (char *) GetMemory(strlen(value) + 1); - strcpy(v->string, value); - //the value - v->value = LibVarStringValue(v->string); - //variable is modified - v->modified = qtrue; -} //end of the function LibVarSet -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -qboolean LibVarChanged(char *var_name) -{ - libvar_t *v; - - v = LibVarGet(var_name); - if (v) - { - return v->modified; - } //end if - else - { - return qfalse; - } //end else -} //end of the function LibVarChanged -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void LibVarSetNotModified(char *var_name) -{ - libvar_t *v; - - v = LibVarGet(var_name); - if (v) - { - v->modified = qfalse; - } //end if -} //end of the function LibVarSetNotModified diff --git a/src/botlib/l_libvar.h b/src/botlib/l_libvar.h deleted file mode 100644 index d437fa22..00000000 --- a/src/botlib/l_libvar.h +++ /dev/null @@ -1,64 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: l_libvar.h - * - * desc: botlib vars - * - * $Archive: /source/code/botlib/l_libvar.h $ - * - *****************************************************************************/ - -//library variable -typedef struct libvar_s -{ - char *name; - char *string; - int flags; - qboolean modified; // set each time the cvar is changed - float value; - struct libvar_s *next; -} libvar_t; - -//removes all library variables -void LibVarDeAllocAll(void); -//gets the library variable with the given name -libvar_t *LibVarGet(char *var_name); -//gets the string of the library variable with the given name -char *LibVarGetString(char *var_name); -//gets the value of the library variable with the given name -float LibVarGetValue(char *var_name); -//creates the library variable if not existing already and returns it -libvar_t *LibVar(char *var_name, char *value); -//creates the library variable if not existing already and returns the value -float LibVarValue(char *var_name, char *value); -//creates the library variable if not existing already and returns the value string -char *LibVarString(char *var_name, char *value); -//sets the library variable -void LibVarSet(char *var_name, char *value); -//returns true if the library variable has been modified -qboolean LibVarChanged(char *var_name); -//sets the library variable to unmodified -void LibVarSetNotModified(char *var_name); - diff --git a/src/botlib/l_log.c b/src/botlib/l_log.c deleted file mode 100644 index ae96a14c..00000000 --- a/src/botlib/l_log.c +++ /dev/null @@ -1,170 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: l_log.c - * - * desc: log file - * - * $Archive: /MissionPack/CODE/botlib/l_log.c $ - * - *****************************************************************************/ - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> - -#include "../qcommon/q_shared.h" -#include "botlib.h" -#include "be_interface.h" //for botimport.Print -#include "l_libvar.h" - -#define MAX_LOGFILENAMESIZE 1024 - -typedef struct logfile_s -{ - char filename[MAX_LOGFILENAMESIZE]; - FILE *fp; - int numwrites; -} logfile_t; - -static logfile_t logfile; - -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void Log_Open(char *filename) -{ - if (!LibVarValue("log", "0")) return; - if (!filename || !strlen(filename)) - { - botimport.Print(PRT_MESSAGE, "openlog <filename>\n"); - return; - } //end if - if (logfile.fp) - { - botimport.Print(PRT_ERROR, "log file %s is already opened\n", logfile.filename); - return; - } //end if - logfile.fp = fopen(filename, "wb"); - if (!logfile.fp) - { - botimport.Print(PRT_ERROR, "can't open the log file %s\n", filename); - return; - } //end if - strncpy(logfile.filename, filename, MAX_LOGFILENAMESIZE); - botimport.Print(PRT_MESSAGE, "Opened log %s\n", logfile.filename); -} //end of the function Log_Create -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void Log_Close(void) -{ - if (!logfile.fp) return; - if (fclose(logfile.fp)) - { - botimport.Print(PRT_ERROR, "can't close log file %s\n", logfile.filename); - return; - } //end if - logfile.fp = NULL; - botimport.Print(PRT_MESSAGE, "Closed log %s\n", logfile.filename); -} //end of the function Log_Close -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void Log_Shutdown(void) -{ - if (logfile.fp) Log_Close(); -} //end of the function Log_Shutdown -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void QDECL Log_Write(char *fmt, ...) -{ - va_list ap; - - if (!logfile.fp) return; - va_start(ap, fmt); - vfprintf(logfile.fp, fmt, ap); - va_end(ap); - //fprintf(logfile.fp, "\r\n"); - fflush(logfile.fp); -} //end of the function Log_Write -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void QDECL Log_WriteTimeStamped(char *fmt, ...) -{ - va_list ap; - - if (!logfile.fp) return; - fprintf(logfile.fp, "%d %02d:%02d:%02d:%02d ", - logfile.numwrites, - (int) (botlibglobals.time / 60 / 60), - (int) (botlibglobals.time / 60), - (int) (botlibglobals.time), - (int) ((int) (botlibglobals.time * 100)) - - ((int) botlibglobals.time) * 100); - va_start(ap, fmt); - vfprintf(logfile.fp, fmt, ap); - va_end(ap); - fprintf(logfile.fp, "\r\n"); - logfile.numwrites++; - fflush(logfile.fp); -} //end of the function Log_Write -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -FILE *Log_FilePointer(void) -{ - return logfile.fp; -} //end of the function Log_FilePointer -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void Log_Flush(void) -{ - if (logfile.fp) fflush(logfile.fp); -} //end of the function Log_Flush - diff --git a/src/botlib/l_log.h b/src/botlib/l_log.h deleted file mode 100644 index 91cbd956..00000000 --- a/src/botlib/l_log.h +++ /dev/null @@ -1,47 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: l_log.h - * - * desc: log file - * - * $Archive: /source/code/botlib/l_log.h $ - * - *****************************************************************************/ - -//open a log file -void Log_Open(char *filename); -//close the current log file -void Log_Close(void); -//close log file if present -void Log_Shutdown(void); -//write to the current opened log file -void QDECL Log_Write(char *fmt, ...); -//write to the current opened log file with a time stamp -void QDECL Log_WriteTimeStamped(char *fmt, ...); -//returns a pointer to the log file -FILE *Log_FilePointer(void); -//flush log file -void Log_Flush(void); - diff --git a/src/botlib/l_memory.c b/src/botlib/l_memory.c deleted file mode 100644 index cb9a4664..00000000 --- a/src/botlib/l_memory.c +++ /dev/null @@ -1,464 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: l_memory.c - * - * desc: memory allocation - * - * $Archive: /MissionPack/code/botlib/l_memory.c $ - * - *****************************************************************************/ - -#include "../qcommon/q_shared.h" -#include "botlib.h" -#include "l_log.h" -#include "be_interface.h" - -//#define MEMDEBUG -//#define MEMORYMANEGER - -#define MEM_ID 0x12345678l -#define HUNK_ID 0x87654321l - -int allocatedmemory; -int totalmemorysize; -int numblocks; - -#ifdef MEMORYMANEGER - -typedef struct memoryblock_s -{ - unsigned long int id; - void *ptr; - int size; -#ifdef MEMDEBUG - char *label; - char *file; - int line; -#endif //MEMDEBUG - struct memoryblock_s *prev, *next; -} memoryblock_t; - -memoryblock_t *memory; - -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void LinkMemoryBlock(memoryblock_t *block) -{ - block->prev = NULL; - block->next = memory; - if (memory) memory->prev = block; - memory = block; -} //end of the function LinkMemoryBlock -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void UnlinkMemoryBlock(memoryblock_t *block) -{ - if (block->prev) block->prev->next = block->next; - else memory = block->next; - if (block->next) block->next->prev = block->prev; -} //end of the function UnlinkMemoryBlock -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -#ifdef MEMDEBUG -void *GetMemoryDebug(unsigned long size, char *label, char *file, int line) -#else -void *GetMemory(unsigned long size) -#endif //MEMDEBUG -{ - void *ptr; - memoryblock_t *block; - assert(botimport.GetMemory); // bk001129 - was NULL'ed - ptr = botimport.GetMemory(size + sizeof(memoryblock_t)); - block = (memoryblock_t *) ptr; - block->id = MEM_ID; - block->ptr = (char *) ptr + sizeof(memoryblock_t); - block->size = size + sizeof(memoryblock_t); -#ifdef MEMDEBUG - block->label = label; - block->file = file; - block->line = line; -#endif //MEMDEBUG - LinkMemoryBlock(block); - allocatedmemory += block->size; - totalmemorysize += block->size + sizeof(memoryblock_t); - numblocks++; - return block->ptr; -} //end of the function GetMemoryDebug -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -#ifdef MEMDEBUG -void *GetClearedMemoryDebug(unsigned long size, char *label, char *file, int line) -#else -void *GetClearedMemory(unsigned long size) -#endif //MEMDEBUG -{ - void *ptr; -#ifdef MEMDEBUG - ptr = GetMemoryDebug(size, label, file, line); -#else - ptr = GetMemory(size); -#endif //MEMDEBUG - Com_Memset(ptr, 0, size); - return ptr; -} //end of the function GetClearedMemory -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -#ifdef MEMDEBUG -void *GetHunkMemoryDebug(unsigned long size, char *label, char *file, int line) -#else -void *GetHunkMemory(unsigned long size) -#endif //MEMDEBUG -{ - void *ptr; - memoryblock_t *block; - - ptr = botimport.HunkAlloc(size + sizeof(memoryblock_t)); - block = (memoryblock_t *) ptr; - block->id = HUNK_ID; - block->ptr = (char *) ptr + sizeof(memoryblock_t); - block->size = size + sizeof(memoryblock_t); -#ifdef MEMDEBUG - block->label = label; - block->file = file; - block->line = line; -#endif //MEMDEBUG - LinkMemoryBlock(block); - allocatedmemory += block->size; - totalmemorysize += block->size + sizeof(memoryblock_t); - numblocks++; - return block->ptr; -} //end of the function GetHunkMemoryDebug -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -#ifdef MEMDEBUG -void *GetClearedHunkMemoryDebug(unsigned long size, char *label, char *file, int line) -#else -void *GetClearedHunkMemory(unsigned long size) -#endif //MEMDEBUG -{ - void *ptr; -#ifdef MEMDEBUG - ptr = GetHunkMemoryDebug(size, label, file, line); -#else - ptr = GetHunkMemory(size); -#endif //MEMDEBUG - Com_Memset(ptr, 0, size); - return ptr; -} //end of the function GetClearedHunkMemory -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -memoryblock_t *BlockFromPointer(void *ptr, char *str) -{ - memoryblock_t *block; - - if (!ptr) - { -#ifdef MEMDEBUG - //char *crash = (char *) NULL; - //crash[0] = 1; - botimport.Print(PRT_FATAL, "%s: NULL pointer\n", str); -#endif // MEMDEBUG - return NULL; - } //end if - block = (memoryblock_t *) ((char *) ptr - sizeof(memoryblock_t)); - if (block->id != MEM_ID && block->id != HUNK_ID) - { - botimport.Print(PRT_FATAL, "%s: invalid memory block\n", str); - return NULL; - } //end if - if (block->ptr != ptr) - { - botimport.Print(PRT_FATAL, "%s: memory block pointer invalid\n", str); - return NULL; - } //end if - return block; -} //end of the function BlockFromPointer -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void FreeMemory(void *ptr) -{ - memoryblock_t *block; - - block = BlockFromPointer(ptr, "FreeMemory"); - if (!block) return; - UnlinkMemoryBlock(block); - allocatedmemory -= block->size; - totalmemorysize -= block->size + sizeof(memoryblock_t); - numblocks--; - // - if (block->id == MEM_ID) - { - botimport.FreeMemory(block); - } //end if -} //end of the function FreeMemory -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AvailableMemory(void) -{ - return botimport.AvailableMemory(); -} //end of the function AvailableMemory -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int MemoryByteSize(void *ptr) -{ - memoryblock_t *block; - - block = BlockFromPointer(ptr, "MemoryByteSize"); - if (!block) return 0; - return block->size; -} //end of the function MemoryByteSize -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void PrintUsedMemorySize(void) -{ - botimport.Print(PRT_MESSAGE, "total allocated memory: %d KB\n", allocatedmemory >> 10); - botimport.Print(PRT_MESSAGE, "total botlib memory: %d KB\n", totalmemorysize >> 10); - botimport.Print(PRT_MESSAGE, "total memory blocks: %d\n", numblocks); -} //end of the function PrintUsedMemorySize -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void PrintMemoryLabels(void) -{ - memoryblock_t *block; - int i; - - PrintUsedMemorySize(); - i = 0; - Log_Write("============= Botlib memory log ==============\r\n"); - Log_Write("\r\n"); - for (block = memory; block; block = block->next) - { -#ifdef MEMDEBUG - if (block->id == HUNK_ID) - { - Log_Write("%6d, hunk %p, %8d: %24s line %6d: %s\r\n", i, block->ptr, block->size, block->file, block->line, block->label); - } //end if - else - { - Log_Write("%6d, %p, %8d: %24s line %6d: %s\r\n", i, block->ptr, block->size, block->file, block->line, block->label); - } //end else -#endif //MEMDEBUG - i++; - } //end for -} //end of the function PrintMemoryLabels -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void DumpMemory(void) -{ - memoryblock_t *block; - - for (block = memory; block; block = memory) - { - FreeMemory(block->ptr); - } //end for - totalmemorysize = 0; - allocatedmemory = 0; -} //end of the function DumpMemory - -#else - -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -#ifdef MEMDEBUG -void *GetMemoryDebug(unsigned long size, char *label, char *file, int line) -#else -void *GetMemory(unsigned long size) -#endif //MEMDEBUG -{ - void *ptr; - unsigned long int *memid; - - ptr = botimport.GetMemory(size + sizeof(unsigned long int)); - if (!ptr) return NULL; - memid = (unsigned long int *) ptr; - *memid = MEM_ID; - return (unsigned long int *) ((char *) ptr + sizeof(unsigned long int)); -} //end of the function GetMemory -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -#ifdef MEMDEBUG -void *GetClearedMemoryDebug(unsigned long size, char *label, char *file, int line) -#else -void *GetClearedMemory(unsigned long size) -#endif //MEMDEBUG -{ - void *ptr; -#ifdef MEMDEBUG - ptr = GetMemoryDebug(size, label, file, line); -#else - ptr = GetMemory(size); -#endif //MEMDEBUG - Com_Memset(ptr, 0, size); - return ptr; -} //end of the function GetClearedMemory -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -#ifdef MEMDEBUG -void *GetHunkMemoryDebug(unsigned long size, char *label, char *file, int line) -#else -void *GetHunkMemory(unsigned long size) -#endif //MEMDEBUG -{ - void *ptr; - unsigned long int *memid; - - ptr = botimport.HunkAlloc(size + sizeof(unsigned long int)); - if (!ptr) return NULL; - memid = (unsigned long int *) ptr; - *memid = HUNK_ID; - return (unsigned long int *) ((char *) ptr + sizeof(unsigned long int)); -} //end of the function GetHunkMemory -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -#ifdef MEMDEBUG -void *GetClearedHunkMemoryDebug(unsigned long size, char *label, char *file, int line) -#else -void *GetClearedHunkMemory(unsigned long size) -#endif //MEMDEBUG -{ - void *ptr; -#ifdef MEMDEBUG - ptr = GetHunkMemoryDebug(size, label, file, line); -#else - ptr = GetHunkMemory(size); -#endif //MEMDEBUG - Com_Memset(ptr, 0, size); - return ptr; -} //end of the function GetClearedHunkMemory -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void FreeMemory(void *ptr) -{ - unsigned long int *memid; - - memid = (unsigned long int *) ((char *) ptr - sizeof(unsigned long int)); - - if (*memid == MEM_ID) - { - botimport.FreeMemory(memid); - } //end if -} //end of the function FreeMemory -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AvailableMemory(void) -{ - return botimport.AvailableMemory(); -} //end of the function AvailableMemory -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void PrintUsedMemorySize(void) -{ -} //end of the function PrintUsedMemorySize -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void PrintMemoryLabels(void) -{ -} //end of the function PrintMemoryLabels - -#endif diff --git a/src/botlib/l_memory.h b/src/botlib/l_memory.h deleted file mode 100644 index cab7cef9..00000000 --- a/src/botlib/l_memory.h +++ /dev/null @@ -1,77 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: l_memory.h - * - * desc: memory management - * - * $Archive: /source/code/botlib/l_memory.h $ - * - *****************************************************************************/ - -//#define MEMDEBUG - -#ifdef MEMDEBUG -#define GetMemory(size) GetMemoryDebug(size, #size, __FILE__, __LINE__); -#define GetClearedMemory(size) GetClearedMemoryDebug(size, #size, __FILE__, __LINE__); -//allocate a memory block of the given size -void *GetMemoryDebug(unsigned long size, char *label, char *file, int line); -//allocate a memory block of the given size and clear it -void *GetClearedMemoryDebug(unsigned long size, char *label, char *file, int line); -// -#define GetHunkMemory(size) GetHunkMemoryDebug(size, #size, __FILE__, __LINE__); -#define GetClearedHunkMemory(size) GetClearedHunkMemoryDebug(size, #size, __FILE__, __LINE__); -//allocate a memory block of the given size -void *GetHunkMemoryDebug(unsigned long size, char *label, char *file, int line); -//allocate a memory block of the given size and clear it -void *GetClearedHunkMemoryDebug(unsigned long size, char *label, char *file, int line); -#else -//allocate a memory block of the given size -void *GetMemory(unsigned long size); -//allocate a memory block of the given size and clear it -void *GetClearedMemory(unsigned long size); -// -#ifdef BSPC -#define GetHunkMemory GetMemory -#define GetClearedHunkMemory GetClearedMemory -#else -//allocate a memory block of the given size -void *GetHunkMemory(unsigned long size); -//allocate a memory block of the given size and clear it -void *GetClearedHunkMemory(unsigned long size); -#endif -#endif - -//free the given memory block -void FreeMemory(void *ptr); -//returns the amount available memory -int AvailableMemory(void); -//prints the total used memory size -void PrintUsedMemorySize(void); -//print all memory blocks with label -void PrintMemoryLabels(void); -//returns the size of the memory block in bytes -int MemoryByteSize(void *ptr); -//free all allocated memory -void DumpMemory(void); diff --git a/src/botlib/l_precomp.c b/src/botlib/l_precomp.c deleted file mode 100644 index 5a0acac0..00000000 --- a/src/botlib/l_precomp.c +++ /dev/null @@ -1,3234 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// - -/***************************************************************************** - * name: l_precomp.c - * - * desc: pre compiler - * - * $Archive: /MissionPack/code/botlib/l_precomp.c $ - * - *****************************************************************************/ - -//Notes: fix: PC_StringizeTokens - -//#define SCREWUP -//#define BOTLIB -//#define QUAKE -//#define QUAKEC -//#define MEQCC - -#ifdef SCREWUP -#include <stdio.h> -#include <stdlib.h> -#include <limits.h> -#include <string.h> -#include <stdarg.h> -#include <time.h> -#include "l_memory.h" -#include "l_script.h" -#include "l_precomp.h" - -typedef enum {qfalse, qtrue} qboolean; -#endif //SCREWUP - -#ifdef BOTLIB -#include "../qcommon/q_shared.h" -#include "botlib.h" -#include "be_interface.h" -#include "l_memory.h" -#include "l_script.h" -#include "l_precomp.h" -#include "l_log.h" -#endif //BOTLIB - -#ifdef MEQCC -#include "qcc.h" -#include "time.h" //time & ctime -#include "math.h" //fabs -#include "l_memory.h" -#include "l_script.h" -#include "l_precomp.h" -#include "l_log.h" - -#define qtrue true -#define qfalse false -#endif //MEQCC - -#ifdef BSPC -//include files for usage in the BSP Converter -#include "../bspc/qbsp.h" -#include "../bspc/l_log.h" -#include "../bspc/l_mem.h" -#include "l_precomp.h" - -#define qtrue true -#define qfalse false -#define Q_stricmp stricmp - -#endif //BSPC - -#if defined(QUAKE) && !defined(BSPC) -#include "l_utils.h" -#endif //QUAKE - -//#define DEBUG_EVAL - -#define MAX_DEFINEPARMS 128 - -#define DEFINEHASHING 1 - -//directive name with parse function -typedef struct directive_s -{ - char *name; - int (*func)(source_t *source); -} directive_t; - -#define DEFINEHASHSIZE 1024 - -#define TOKEN_HEAP_SIZE 4096 - -int numtokens; -/* -int tokenheapinitialized; //true when the token heap is initialized -token_t token_heap[TOKEN_HEAP_SIZE]; //heap with tokens -token_t *freetokens; //free tokens from the heap -*/ - -//list with global defines added to every source loaded -define_t *globaldefines; - -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void QDECL SourceError(source_t *source, char *str, ...) -{ - char text[1024]; - va_list ap; - - va_start(ap, str); - vsprintf(text, str, ap); - va_end(ap); -#ifdef BOTLIB - botimport.Print(PRT_ERROR, "file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text); -#endif //BOTLIB -#ifdef MEQCC - printf("error: file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text); -#endif //MEQCC -#ifdef BSPC - Log_Print("error: file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text); -#endif //BSPC -} //end of the function SourceError -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void QDECL SourceWarning(source_t *source, char *str, ...) -{ - char text[1024]; - va_list ap; - - va_start(ap, str); - vsprintf(text, str, ap); - va_end(ap); -#ifdef BOTLIB - botimport.Print(PRT_WARNING, "file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text); -#endif //BOTLIB -#ifdef MEQCC - printf("warning: file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text); -#endif //MEQCC -#ifdef BSPC - Log_Print("warning: file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text); -#endif //BSPC -} //end of the function ScriptWarning -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_PushIndent(source_t *source, int type, int skip) -{ - indent_t *indent; - - indent = (indent_t *) GetMemory(sizeof(indent_t)); - indent->type = type; - indent->script = source->scriptstack; - indent->skip = (skip != 0); - source->skip += indent->skip; - indent->next = source->indentstack; - source->indentstack = indent; -} //end of the function PC_PushIndent -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_PopIndent(source_t *source, int *type, int *skip) -{ - indent_t *indent; - - *type = 0; - *skip = 0; - - indent = source->indentstack; - if (!indent) return; - - //must be an indent from the current script - if (source->indentstack->script != source->scriptstack) return; - - *type = indent->type; - *skip = indent->skip; - source->indentstack = source->indentstack->next; - source->skip -= indent->skip; - FreeMemory(indent); -} //end of the function PC_PopIndent -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_PushScript(source_t *source, script_t *script) -{ - script_t *s; - - for (s = source->scriptstack; s; s = s->next) - { - if (!Q_stricmp(s->filename, script->filename)) - { - SourceError(source, "%s recursively included", script->filename); - return; - } //end if - } //end for - //push the script on the script stack - script->next = source->scriptstack; - source->scriptstack = script; -} //end of the function PC_PushScript -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_InitTokenHeap(void) -{ - /* - int i; - - if (tokenheapinitialized) return; - freetokens = NULL; - for (i = 0; i < TOKEN_HEAP_SIZE; i++) - { - token_heap[i].next = freetokens; - freetokens = &token_heap[i]; - } //end for - tokenheapinitialized = qtrue; - */ -} //end of the function PC_InitTokenHeap -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -token_t *PC_CopyToken(token_t *token) -{ - token_t *t; - -// t = (token_t *) malloc(sizeof(token_t)); - t = (token_t *) GetMemory(sizeof(token_t)); -// t = freetokens; - if (!t) - { -#ifdef BSPC - Error("out of token space\n"); -#else - Com_Error(ERR_FATAL, "out of token space\n"); -#endif - return NULL; - } //end if -// freetokens = freetokens->next; - Com_Memcpy(t, token, sizeof(token_t)); - t->next = NULL; - numtokens++; - return t; -} //end of the function PC_CopyToken -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_FreeToken(token_t *token) -{ - //free(token); - FreeMemory(token); -// token->next = freetokens; -// freetokens = token; - numtokens--; -} //end of the function PC_FreeToken -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_ReadSourceToken(source_t *source, token_t *token) -{ - token_t *t; - script_t *script; - int type, skip; - - //if there's no token already available - while(!source->tokens) - { - //if there's a token to read from the script - if (PS_ReadToken(source->scriptstack, token)) return qtrue; - //if at the end of the script - if (EndOfScript(source->scriptstack)) - { - //remove all indents of the script - while(source->indentstack && - source->indentstack->script == source->scriptstack) - { - SourceWarning(source, "missing #endif"); - PC_PopIndent(source, &type, &skip); - } //end if - } //end if - //if this was the initial script - if (!source->scriptstack->next) return qfalse; - //remove the script and return to the last one - script = source->scriptstack; - source->scriptstack = source->scriptstack->next; - FreeScript(script); - } //end while - //copy the already available token - Com_Memcpy(token, source->tokens, sizeof(token_t)); - //free the read token - t = source->tokens; - source->tokens = source->tokens->next; - PC_FreeToken(t); - return qtrue; -} //end of the function PC_ReadSourceToken -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_UnreadSourceToken(source_t *source, token_t *token) -{ - token_t *t; - - t = PC_CopyToken(token); - t->next = source->tokens; - source->tokens = t; - return qtrue; -} //end of the function PC_UnreadSourceToken -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_ReadDefineParms(source_t *source, define_t *define, token_t **parms, int maxparms) -{ - token_t token, *t, *last; - int i, done, lastcomma, numparms, indent; - - if (!PC_ReadSourceToken(source, &token)) - { - SourceError(source, "define %s missing parms", define->name); - return qfalse; - } //end if - // - if (define->numparms > maxparms) - { - SourceError(source, "define with more than %d parameters", maxparms); - return qfalse; - } //end if - // - for (i = 0; i < define->numparms; i++) parms[i] = NULL; - //if no leading "(" - if (strcmp(token.string, "(")) - { - PC_UnreadSourceToken(source, &token); - SourceError(source, "define %s missing parms", define->name); - return qfalse; - } //end if - //read the define parameters - for (done = 0, numparms = 0, indent = 0; !done;) - { - if (numparms >= maxparms) - { - SourceError(source, "define %s with too many parms", define->name); - return qfalse; - } //end if - if (numparms >= define->numparms) - { - SourceWarning(source, "define %s has too many parms", define->name); - return qfalse; - } //end if - parms[numparms] = NULL; - lastcomma = 1; - last = NULL; - while(!done) - { - // - if (!PC_ReadSourceToken(source, &token)) - { - SourceError(source, "define %s incomplete", define->name); - return qfalse; - } //end if - // - if (!strcmp(token.string, ",")) - { - if (indent <= 0) - { - if (lastcomma) SourceWarning(source, "too many comma's"); - lastcomma = 1; - break; - } //end if - } //end if - lastcomma = 0; - // - if (!strcmp(token.string, "(")) - { - indent++; - continue; - } //end if - else if (!strcmp(token.string, ")")) - { - if (--indent <= 0) - { - if (!parms[define->numparms-1]) - { - SourceWarning(source, "too few define parms"); - } //end if - done = 1; - break; - } //end if - } //end if - // - if (numparms < define->numparms) - { - // - t = PC_CopyToken(&token); - t->next = NULL; - if (last) last->next = t; - else parms[numparms] = t; - last = t; - } //end if - } //end while - numparms++; - } //end for - return qtrue; -} //end of the function PC_ReadDefineParms -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_StringizeTokens(token_t *tokens, token_t *token) -{ - token_t *t; - - token->type = TT_STRING; - token->whitespace_p = NULL; - token->endwhitespace_p = NULL; - token->string[0] = '\0'; - strcat(token->string, "\""); - for (t = tokens; t; t = t->next) - { - strncat(token->string, t->string, MAX_TOKEN - strlen(token->string)); - } //end for - strncat(token->string, "\"", MAX_TOKEN - strlen(token->string)); - return qtrue; -} //end of the function PC_StringizeTokens -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_MergeTokens(token_t *t1, token_t *t2) -{ - //merging of a name with a name or number - if (t1->type == TT_NAME && (t2->type == TT_NAME || t2->type == TT_NUMBER)) - { - strcat(t1->string, t2->string); - return qtrue; - } //end if - //merging of two strings - if (t1->type == TT_STRING && t2->type == TT_STRING) - { - //remove trailing double quote - t1->string[strlen(t1->string)-1] = '\0'; - //concat without leading double quote - strcat(t1->string, &t2->string[1]); - return qtrue; - } //end if - //FIXME: merging of two number of the same sub type - return qfalse; -} //end of the function PC_MergeTokens -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -/* -void PC_PrintDefine(define_t *define) -{ - printf("define->name = %s\n", define->name); - printf("define->flags = %d\n", define->flags); - printf("define->builtin = %d\n", define->builtin); - printf("define->numparms = %d\n", define->numparms); -// token_t *parms; //define parameters -// token_t *tokens; //macro tokens (possibly containing parm tokens) -// struct define_s *next; //next defined macro in a list -} //end of the function PC_PrintDefine*/ -#if DEFINEHASHING -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_PrintDefineHashTable(define_t **definehash) -{ - int i; - define_t *d; - - for (i = 0; i < DEFINEHASHSIZE; i++) - { - Log_Write("%4d:", i); - for (d = definehash[i]; d; d = d->hashnext) - { - Log_Write(" %s", d->name); - } //end for - Log_Write("\n"); - } //end for -} //end of the function PC_PrintDefineHashTable -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -//char primes[16] = {1, 3, 5, 7, 11, 13, 17, 19, 23, 27, 29, 31, 37, 41, 43, 47}; - -int PC_NameHash(char *name) -{ - int register hash, i; - - hash = 0; - for (i = 0; name[i] != '\0'; i++) - { - hash += name[i] * (119 + i); - //hash += (name[i] << 7) + i; - //hash += (name[i] << (i&15)); - } //end while - hash = (hash ^ (hash >> 10) ^ (hash >> 20)) & (DEFINEHASHSIZE-1); - return hash; -} //end of the function PC_NameHash -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_AddDefineToHash(define_t *define, define_t **definehash) -{ - int hash; - - hash = PC_NameHash(define->name); - define->hashnext = definehash[hash]; - definehash[hash] = define; -} //end of the function PC_AddDefineToHash -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -define_t *PC_FindHashedDefine(define_t **definehash, char *name) -{ - define_t *d; - int hash; - - hash = PC_NameHash(name); - for (d = definehash[hash]; d; d = d->hashnext) - { - if (!strcmp(d->name, name)) return d; - } //end for - return NULL; -} //end of the function PC_FindHashedDefine -#endif //DEFINEHASHING -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -define_t *PC_FindDefine(define_t *defines, char *name) -{ - define_t *d; - - for (d = defines; d; d = d->next) - { - if (!strcmp(d->name, name)) return d; - } //end for - return NULL; -} //end of the function PC_FindDefine -//============================================================================ -// -// Parameter: - -// Returns: number of the parm -// if no parm found with the given name -1 is returned -// Changes Globals: - -//============================================================================ -int PC_FindDefineParm(define_t *define, char *name) -{ - token_t *p; - int i; - - i = 0; - for (p = define->parms; p; p = p->next) - { - if (!strcmp(p->string, name)) return i; - i++; - } //end for - return -1; -} //end of the function PC_FindDefineParm -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_FreeDefine(define_t *define) -{ - token_t *t, *next; - - //free the define parameters - for (t = define->parms; t; t = next) - { - next = t->next; - PC_FreeToken(t); - } //end for - //free the define tokens - for (t = define->tokens; t; t = next) - { - next = t->next; - PC_FreeToken(t); - } //end for - //free the define - FreeMemory(define); -} //end of the function PC_FreeDefine -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_AddBuiltinDefines(source_t *source) -{ - int i; - define_t *define; - struct builtin - { - char *string; - int builtin; - } builtin[] = { // bk001204 - brackets - { "__LINE__", BUILTIN_LINE }, - { "__FILE__", BUILTIN_FILE }, - { "__DATE__", BUILTIN_DATE }, - { "__TIME__", BUILTIN_TIME }, -// { "__STDC__", BUILTIN_STDC }, - { NULL, 0 } - }; - - for (i = 0; builtin[i].string; i++) - { - define = (define_t *) GetMemory(sizeof(define_t) + strlen(builtin[i].string) + 1); - Com_Memset(define, 0, sizeof(define_t)); - define->name = (char *) define + sizeof(define_t); - strcpy(define->name, builtin[i].string); - define->flags |= DEFINE_FIXED; - define->builtin = builtin[i].builtin; - //add the define to the source -#if DEFINEHASHING - PC_AddDefineToHash(define, source->definehash); -#else - define->next = source->defines; - source->defines = define; -#endif //DEFINEHASHING - } //end for -} //end of the function PC_AddBuiltinDefines -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_ExpandBuiltinDefine(source_t *source, token_t *deftoken, define_t *define, - token_t **firsttoken, token_t **lasttoken) -{ - token_t *token; -#ifdef _WIN32 - unsigned long t; // time_t t; //to prevent LCC warning -#else - time_t t; -#endif - - char *curtime; - - token = PC_CopyToken(deftoken); - switch(define->builtin) - { - case BUILTIN_LINE: - { - sprintf(token->string, "%d", deftoken->line); -#ifdef NUMBERVALUE - token->intvalue = deftoken->line; - token->floatvalue = deftoken->line; -#endif //NUMBERVALUE - token->type = TT_NUMBER; - token->subtype = TT_DECIMAL | TT_INTEGER; - *firsttoken = token; - *lasttoken = token; - break; - } //end case - case BUILTIN_FILE: - { - strcpy(token->string, source->scriptstack->filename); - token->type = TT_NAME; - token->subtype = strlen(token->string); - *firsttoken = token; - *lasttoken = token; - break; - } //end case - case BUILTIN_DATE: - { - t = time(NULL); - curtime = ctime(&t); - strcpy(token->string, "\""); - strncat(token->string, curtime+4, 7); - strncat(token->string+7, curtime+20, 4); - strcat(token->string, "\""); - free(curtime); - token->type = TT_NAME; - token->subtype = strlen(token->string); - *firsttoken = token; - *lasttoken = token; - break; - } //end case - case BUILTIN_TIME: - { - t = time(NULL); - curtime = ctime(&t); - strcpy(token->string, "\""); - strncat(token->string, curtime+11, 8); - strcat(token->string, "\""); - free(curtime); - token->type = TT_NAME; - token->subtype = strlen(token->string); - *firsttoken = token; - *lasttoken = token; - break; - } //end case - case BUILTIN_STDC: - default: - { - *firsttoken = NULL; - *lasttoken = NULL; - break; - } //end case - } //end switch - return qtrue; -} //end of the function PC_ExpandBuiltinDefine -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_ExpandDefine(source_t *source, token_t *deftoken, define_t *define, - token_t **firsttoken, token_t **lasttoken) -{ - token_t *parms[MAX_DEFINEPARMS], *dt, *pt, *t; - token_t *t1, *t2, *first, *last, *nextpt, token; - int parmnum, i; - - //if it is a builtin define - if (define->builtin) - { - return PC_ExpandBuiltinDefine(source, deftoken, define, firsttoken, lasttoken); - } //end if - //if the define has parameters - if (define->numparms) - { - if (!PC_ReadDefineParms(source, define, parms, MAX_DEFINEPARMS)) return qfalse; -#ifdef DEBUG_EVAL - for (i = 0; i < define->numparms; i++) - { - Log_Write("define parms %d:", i); - for (pt = parms[i]; pt; pt = pt->next) - { - Log_Write("%s", pt->string); - } //end for - } //end for -#endif //DEBUG_EVAL - } //end if - //empty list at first - first = NULL; - last = NULL; - //create a list with tokens of the expanded define - for (dt = define->tokens; dt; dt = dt->next) - { - parmnum = -1; - //if the token is a name, it could be a define parameter - if (dt->type == TT_NAME) - { - parmnum = PC_FindDefineParm(define, dt->string); - } //end if - //if it is a define parameter - if (parmnum >= 0) - { - for (pt = parms[parmnum]; pt; pt = pt->next) - { - t = PC_CopyToken(pt); - //add the token to the list - t->next = NULL; - if (last) last->next = t; - else first = t; - last = t; - } //end for - } //end if - else - { - //if stringizing operator - if (dt->string[0] == '#' && dt->string[1] == '\0') - { - //the stringizing operator must be followed by a define parameter - if (dt->next) parmnum = PC_FindDefineParm(define, dt->next->string); - else parmnum = -1; - // - if (parmnum >= 0) - { - //step over the stringizing operator - dt = dt->next; - //stringize the define parameter tokens - if (!PC_StringizeTokens(parms[parmnum], &token)) - { - SourceError(source, "can't stringize tokens"); - return qfalse; - } //end if - t = PC_CopyToken(&token); - } //end if - else - { - SourceWarning(source, "stringizing operator without define parameter"); - continue; - } //end if - } //end if - else - { - t = PC_CopyToken(dt); - } //end else - //add the token to the list - t->next = NULL; - if (last) last->next = t; - else first = t; - last = t; - } //end else - } //end for - //check for the merging operator - for (t = first; t; ) - { - if (t->next) - { - //if the merging operator - if (t->next->string[0] == '#' && t->next->string[1] == '#') - { - t1 = t; - t2 = t->next->next; - if (t2) - { - if (!PC_MergeTokens(t1, t2)) - { - SourceError(source, "can't merge %s with %s", t1->string, t2->string); - return qfalse; - } //end if - PC_FreeToken(t1->next); - t1->next = t2->next; - if (t2 == last) last = t1; - PC_FreeToken(t2); - continue; - } //end if - } //end if - } //end if - t = t->next; - } //end for - //store the first and last token of the list - *firsttoken = first; - *lasttoken = last; - //free all the parameter tokens - for (i = 0; i < define->numparms; i++) - { - for (pt = parms[i]; pt; pt = nextpt) - { - nextpt = pt->next; - PC_FreeToken(pt); - } //end for - } //end for - // - return qtrue; -} //end of the function PC_ExpandDefine -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_ExpandDefineIntoSource(source_t *source, token_t *deftoken, define_t *define) -{ - token_t *firsttoken, *lasttoken; - - if (!PC_ExpandDefine(source, deftoken, define, &firsttoken, &lasttoken)) return qfalse; - - if (firsttoken && lasttoken) - { - lasttoken->next = source->tokens; - source->tokens = firsttoken; - return qtrue; - } //end if - return qfalse; -} //end of the function PC_ExpandDefineIntoSource -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_ConvertPath(char *path) -{ - char *ptr; - - //remove double path seperators - for (ptr = path; *ptr;) - { - if ((*ptr == '\\' || *ptr == '/') && - (*(ptr+1) == '\\' || *(ptr+1) == '/')) - { - strcpy(ptr, ptr+1); - } //end if - else - { - ptr++; - } //end else - } //end while - //set OS dependent path seperators - for (ptr = path; *ptr;) - { - if (*ptr == '/' || *ptr == '\\') *ptr = PATHSEPERATOR_CHAR; - ptr++; - } //end while -} //end of the function PC_ConvertPath -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_Directive_include(source_t *source) -{ - script_t *script; - token_t token; - char path[MAX_PATH]; -#ifdef QUAKE - foundfile_t file; -#endif //QUAKE - - if (source->skip > 0) return qtrue; - // - if (!PC_ReadSourceToken(source, &token)) - { - SourceError(source, "#include without file name"); - return qfalse; - } //end if - if (token.linescrossed > 0) - { - SourceError(source, "#include without file name"); - return qfalse; - } //end if - if (token.type == TT_STRING) - { - StripDoubleQuotes(token.string); - PC_ConvertPath(token.string); - script = LoadScriptFile(token.string); - if (!script) - { - strcpy(path, source->includepath); - strcat(path, token.string); - script = LoadScriptFile(path); - } //end if - } //end if - else if (token.type == TT_PUNCTUATION && *token.string == '<') - { - strcpy(path, source->includepath); - while(PC_ReadSourceToken(source, &token)) - { - if (token.linescrossed > 0) - { - PC_UnreadSourceToken(source, &token); - break; - } //end if - if (token.type == TT_PUNCTUATION && *token.string == '>') break; - strncat(path, token.string, MAX_PATH); - } //end while - if (*token.string != '>') - { - SourceWarning(source, "#include missing trailing >"); - } //end if - if (!strlen(path)) - { - SourceError(source, "#include without file name between < >"); - return qfalse; - } //end if - PC_ConvertPath(path); - script = LoadScriptFile(path); - } //end if - else - { - SourceError(source, "#include without file name"); - return qfalse; - } //end else -#ifdef QUAKE - if (!script) - { - Com_Memset(&file, 0, sizeof(foundfile_t)); - script = LoadScriptFile(path); - if (script) strncpy(script->filename, path, MAX_PATH); - } //end if -#endif //QUAKE - if (!script) - { -#ifdef SCREWUP - SourceWarning(source, "file %s not found", path); - return qtrue; -#else - SourceError(source, "file %s not found", path); - return qfalse; -#endif //SCREWUP - } //end if - PC_PushScript(source, script); - return qtrue; -} //end of the function PC_Directive_include -//============================================================================ -// reads a token from the current line, continues reading on the next -// line only if a backslash '\' is encountered. -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_ReadLine(source_t *source, token_t *token) -{ - int crossline; - - crossline = 0; - do - { - if (!PC_ReadSourceToken(source, token)) return qfalse; - - if (token->linescrossed > crossline) - { - PC_UnreadSourceToken(source, token); - return qfalse; - } //end if - crossline = 1; - } while(!strcmp(token->string, "\\")); - return qtrue; -} //end of the function PC_ReadLine -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_WhiteSpaceBeforeToken(token_t *token) -{ - return token->endwhitespace_p - token->whitespace_p > 0; -} //end of the function PC_WhiteSpaceBeforeToken -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_ClearTokenWhiteSpace(token_t *token) -{ - token->whitespace_p = NULL; - token->endwhitespace_p = NULL; - token->linescrossed = 0; -} //end of the function PC_ClearTokenWhiteSpace -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_Directive_undef(source_t *source) -{ - token_t token; - define_t *define, *lastdefine; - int hash; - - if (source->skip > 0) return qtrue; - // - if (!PC_ReadLine(source, &token)) - { - SourceError(source, "undef without name"); - return qfalse; - } //end if - if (token.type != TT_NAME) - { - PC_UnreadSourceToken(source, &token); - SourceError(source, "expected name, found %s", token.string); - return qfalse; - } //end if -#if DEFINEHASHING - - hash = PC_NameHash(token.string); - for (lastdefine = NULL, define = source->definehash[hash]; define; define = define->hashnext) - { - if (!strcmp(define->name, token.string)) - { - if (define->flags & DEFINE_FIXED) - { - SourceWarning(source, "can't undef %s", token.string); - } //end if - else - { - if (lastdefine) lastdefine->hashnext = define->hashnext; - else source->definehash[hash] = define->hashnext; - PC_FreeDefine(define); - } //end else - break; - } //end if - lastdefine = define; - } //end for -#else //DEFINEHASHING - for (lastdefine = NULL, define = source->defines; define; define = define->next) - { - if (!strcmp(define->name, token.string)) - { - if (define->flags & DEFINE_FIXED) - { - SourceWarning(source, "can't undef %s", token.string); - } //end if - else - { - if (lastdefine) lastdefine->next = define->next; - else source->defines = define->next; - PC_FreeDefine(define); - } //end else - break; - } //end if - lastdefine = define; - } //end for -#endif //DEFINEHASHING - return qtrue; -} //end of the function PC_Directive_undef -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_Directive_define(source_t *source) -{ - token_t token, *t, *last; - define_t *define; - - if (source->skip > 0) return qtrue; - // - if (!PC_ReadLine(source, &token)) - { - SourceError(source, "#define without name"); - return qfalse; - } //end if - if (token.type != TT_NAME) - { - PC_UnreadSourceToken(source, &token); - SourceError(source, "expected name after #define, found %s", token.string); - return qfalse; - } //end if - //check if the define already exists -#if DEFINEHASHING - define = PC_FindHashedDefine(source->definehash, token.string); -#else - define = PC_FindDefine(source->defines, token.string); -#endif //DEFINEHASHING - if (define) - { - if (define->flags & DEFINE_FIXED) - { - SourceError(source, "can't redefine %s", token.string); - return qfalse; - } //end if - SourceWarning(source, "redefinition of %s", token.string); - //unread the define name before executing the #undef directive - PC_UnreadSourceToken(source, &token); - if (!PC_Directive_undef(source)) return qfalse; - //if the define was not removed (define->flags & DEFINE_FIXED) -#if DEFINEHASHING - define = PC_FindHashedDefine(source->definehash, token.string); -#else - define = PC_FindDefine(source->defines, token.string); -#endif //DEFINEHASHING - } //end if - //allocate define - define = (define_t *) GetMemory(sizeof(define_t) + strlen(token.string) + 1); - Com_Memset(define, 0, sizeof(define_t)); - define->name = (char *) define + sizeof(define_t); - strcpy(define->name, token.string); - //add the define to the source -#if DEFINEHASHING - PC_AddDefineToHash(define, source->definehash); -#else //DEFINEHASHING - define->next = source->defines; - source->defines = define; -#endif //DEFINEHASHING - //if nothing is defined, just return - if (!PC_ReadLine(source, &token)) return qtrue; - //if it is a define with parameters - if (!PC_WhiteSpaceBeforeToken(&token) && !strcmp(token.string, "(")) - { - //read the define parameters - last = NULL; - if (!PC_CheckTokenString(source, ")")) - { - while(1) - { - if (!PC_ReadLine(source, &token)) - { - SourceError(source, "expected define parameter"); - return qfalse; - } //end if - //if it isn't a name - if (token.type != TT_NAME) - { - SourceError(source, "invalid define parameter"); - return qfalse; - } //end if - // - if (PC_FindDefineParm(define, token.string) >= 0) - { - SourceError(source, "two the same define parameters"); - return qfalse; - } //end if - //add the define parm - t = PC_CopyToken(&token); - PC_ClearTokenWhiteSpace(t); - t->next = NULL; - if (last) last->next = t; - else define->parms = t; - last = t; - define->numparms++; - //read next token - if (!PC_ReadLine(source, &token)) - { - SourceError(source, "define parameters not terminated"); - return qfalse; - } //end if - // - if (!strcmp(token.string, ")")) break; - //then it must be a comma - if (strcmp(token.string, ",")) - { - SourceError(source, "define not terminated"); - return qfalse; - } //end if - } //end while - } //end if - if (!PC_ReadLine(source, &token)) return qtrue; - } //end if - //read the defined stuff - last = NULL; - do - { - t = PC_CopyToken(&token); - if (t->type == TT_NAME && !strcmp(t->string, define->name)) - { - SourceError(source, "recursive define (removed recursion)"); - continue; - } //end if - PC_ClearTokenWhiteSpace(t); - t->next = NULL; - if (last) last->next = t; - else define->tokens = t; - last = t; - } while(PC_ReadLine(source, &token)); - // - if (last) - { - //check for merge operators at the beginning or end - if (!strcmp(define->tokens->string, "##") || - !strcmp(last->string, "##")) - { - SourceError(source, "define with misplaced ##"); - return qfalse; - } //end if - } //end if - return qtrue; -} //end of the function PC_Directive_define -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -define_t *PC_DefineFromString(char *string) -{ - script_t *script; - source_t src; - token_t *t; - int res, i; - define_t *def; - - PC_InitTokenHeap(); - - script = LoadScriptMemory(string, strlen(string), "*extern"); - //create a new source - Com_Memset(&src, 0, sizeof(source_t)); - strncpy(src.filename, "*extern", MAX_PATH); - src.scriptstack = script; -#if DEFINEHASHING - src.definehash = GetClearedMemory(DEFINEHASHSIZE * sizeof(define_t *)); -#endif //DEFINEHASHING - //create a define from the source - res = PC_Directive_define(&src); - //free any tokens if left - for (t = src.tokens; t; t = src.tokens) - { - src.tokens = src.tokens->next; - PC_FreeToken(t); - } //end for -#ifdef DEFINEHASHING - def = NULL; - for (i = 0; i < DEFINEHASHSIZE; i++) - { - if (src.definehash[i]) - { - def = src.definehash[i]; - break; - } //end if - } //end for -#else - def = src.defines; -#endif //DEFINEHASHING - // -#if DEFINEHASHING - FreeMemory(src.definehash); -#endif //DEFINEHASHING - // - FreeScript(script); - //if the define was created succesfully - if (res > 0) return def; - //free the define is created - if (src.defines) PC_FreeDefine(def); - // - return NULL; -} //end of the function PC_DefineFromString -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_AddDefine(source_t *source, char *string) -{ - define_t *define; - - define = PC_DefineFromString(string); - if (!define) return qfalse; -#if DEFINEHASHING - PC_AddDefineToHash(define, source->definehash); -#else //DEFINEHASHING - define->next = source->defines; - source->defines = define; -#endif //DEFINEHASHING - return qtrue; -} //end of the function PC_AddDefine -//============================================================================ -// add a globals define that will be added to all opened sources -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_AddGlobalDefine(char *string) -{ - define_t *define; - - define = PC_DefineFromString(string); - if (!define) return qfalse; - define->next = globaldefines; - globaldefines = define; - return qtrue; -} //end of the function PC_AddGlobalDefine -//============================================================================ -// remove the given global define -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_RemoveGlobalDefine(char *name) -{ - define_t *define; - - define = PC_FindDefine(globaldefines, name); - if (define) - { - PC_FreeDefine(define); - return qtrue; - } //end if - return qfalse; -} //end of the function PC_RemoveGlobalDefine -//============================================================================ -// remove all globals defines -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_RemoveAllGlobalDefines(void) -{ - define_t *define; - - for (define = globaldefines; define; define = globaldefines) - { - globaldefines = globaldefines->next; - PC_FreeDefine(define); - } //end for -} //end of the function PC_RemoveAllGlobalDefines -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -define_t *PC_CopyDefine(source_t *source, define_t *define) -{ - define_t *newdefine; - token_t *token, *newtoken, *lasttoken; - - newdefine = (define_t *) GetMemory(sizeof(define_t) + strlen(define->name) + 1); - //copy the define name - newdefine->name = (char *) newdefine + sizeof(define_t); - strcpy(newdefine->name, define->name); - newdefine->flags = define->flags; - newdefine->builtin = define->builtin; - newdefine->numparms = define->numparms; - //the define is not linked - newdefine->next = NULL; - newdefine->hashnext = NULL; - //copy the define tokens - newdefine->tokens = NULL; - for (lasttoken = NULL, token = define->tokens; token; token = token->next) - { - newtoken = PC_CopyToken(token); - newtoken->next = NULL; - if (lasttoken) lasttoken->next = newtoken; - else newdefine->tokens = newtoken; - lasttoken = newtoken; - } //end for - //copy the define parameters - newdefine->parms = NULL; - for (lasttoken = NULL, token = define->parms; token; token = token->next) - { - newtoken = PC_CopyToken(token); - newtoken->next = NULL; - if (lasttoken) lasttoken->next = newtoken; - else newdefine->parms = newtoken; - lasttoken = newtoken; - } //end for - return newdefine; -} //end of the function PC_CopyDefine -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_AddGlobalDefinesToSource(source_t *source) -{ - define_t *define, *newdefine; - - for (define = globaldefines; define; define = define->next) - { - newdefine = PC_CopyDefine(source, define); -#if DEFINEHASHING - PC_AddDefineToHash(newdefine, source->definehash); -#else //DEFINEHASHING - newdefine->next = source->defines; - source->defines = newdefine; -#endif //DEFINEHASHING - } //end for -} //end of the function PC_AddGlobalDefinesToSource -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_Directive_if_def(source_t *source, int type) -{ - token_t token; - define_t *d; - int skip; - - if (!PC_ReadLine(source, &token)) - { - SourceError(source, "#ifdef without name"); - return qfalse; - } //end if - if (token.type != TT_NAME) - { - PC_UnreadSourceToken(source, &token); - SourceError(source, "expected name after #ifdef, found %s", token.string); - return qfalse; - } //end if -#if DEFINEHASHING - d = PC_FindHashedDefine(source->definehash, token.string); -#else - d = PC_FindDefine(source->defines, token.string); -#endif //DEFINEHASHING - skip = (type == INDENT_IFDEF) == (d == NULL); - PC_PushIndent(source, type, skip); - return qtrue; -} //end of the function PC_Directiveif_def -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_Directive_ifdef(source_t *source) -{ - return PC_Directive_if_def(source, INDENT_IFDEF); -} //end of the function PC_Directive_ifdef -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_Directive_ifndef(source_t *source) -{ - return PC_Directive_if_def(source, INDENT_IFNDEF); -} //end of the function PC_Directive_ifndef -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_Directive_else(source_t *source) -{ - int type, skip; - - PC_PopIndent(source, &type, &skip); - if (!type) - { - SourceError(source, "misplaced #else"); - return qfalse; - } //end if - if (type == INDENT_ELSE) - { - SourceError(source, "#else after #else"); - return qfalse; - } //end if - PC_PushIndent(source, INDENT_ELSE, !skip); - return qtrue; -} //end of the function PC_Directive_else -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_Directive_endif(source_t *source) -{ - int type, skip; - - PC_PopIndent(source, &type, &skip); - if (!type) - { - SourceError(source, "misplaced #endif"); - return qfalse; - } //end if - return qtrue; -} //end of the function PC_Directive_endif -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -typedef struct operator_s -{ - int operator; - int priority; - int parentheses; - struct operator_s *prev, *next; -} operator_t; - -typedef struct value_s -{ - signed long int intvalue; - double floatvalue; - int parentheses; - struct value_s *prev, *next; -} value_t; - -int PC_OperatorPriority(int op) -{ - switch(op) - { - case P_MUL: return 15; - case P_DIV: return 15; - case P_MOD: return 15; - case P_ADD: return 14; - case P_SUB: return 14; - - case P_LOGIC_AND: return 7; - case P_LOGIC_OR: return 6; - case P_LOGIC_GEQ: return 12; - case P_LOGIC_LEQ: return 12; - case P_LOGIC_EQ: return 11; - case P_LOGIC_UNEQ: return 11; - - case P_LOGIC_NOT: return 16; - case P_LOGIC_GREATER: return 12; - case P_LOGIC_LESS: return 12; - - case P_RSHIFT: return 13; - case P_LSHIFT: return 13; - - case P_BIN_AND: return 10; - case P_BIN_OR: return 8; - case P_BIN_XOR: return 9; - case P_BIN_NOT: return 16; - - case P_COLON: return 5; - case P_QUESTIONMARK: return 5; - } //end switch - return qfalse; -} //end of the function PC_OperatorPriority - -//#define AllocValue() GetClearedMemory(sizeof(value_t)); -//#define FreeValue(val) FreeMemory(val) -//#define AllocOperator(op) op = (operator_t *) GetClearedMemory(sizeof(operator_t)); -//#define FreeOperator(op) FreeMemory(op); - -#define MAX_VALUES 64 -#define MAX_OPERATORS 64 -#define AllocValue(val) \ - if (numvalues >= MAX_VALUES) { \ - SourceError(source, "out of value space\n"); \ - error = 1; \ - break; \ - } \ - else \ - val = &value_heap[numvalues++]; -#define FreeValue(val) -// -#define AllocOperator(op) \ - if (numoperators >= MAX_OPERATORS) { \ - SourceError(source, "out of operator space\n"); \ - error = 1; \ - break; \ - } \ - else \ - op = &operator_heap[numoperators++]; -#define FreeOperator(op) - -int PC_EvaluateTokens(source_t *source, token_t *tokens, signed long int *intvalue, - double *floatvalue, int integer) -{ - operator_t *o, *firstoperator, *lastoperator; - value_t *v, *firstvalue, *lastvalue, *v1, *v2; - token_t *t; - int brace = 0; - int parentheses = 0; - int error = 0; - int lastwasvalue = 0; - int negativevalue = 0; - int questmarkintvalue = 0; - double questmarkfloatvalue = 0; - int gotquestmarkvalue = qfalse; - int lastoperatortype = 0; - // - operator_t operator_heap[MAX_OPERATORS]; - int numoperators = 0; - value_t value_heap[MAX_VALUES]; - int numvalues = 0; - - firstoperator = lastoperator = NULL; - firstvalue = lastvalue = NULL; - if (intvalue) *intvalue = 0; - if (floatvalue) *floatvalue = 0; - for (t = tokens; t; t = t->next) - { - switch(t->type) - { - case TT_NAME: - { - if (lastwasvalue || negativevalue) - { - SourceError(source, "syntax error in #if/#elif"); - error = 1; - break; - } //end if - if (strcmp(t->string, "defined")) - { - SourceError(source, "undefined name %s in #if/#elif", t->string); - error = 1; - break; - } //end if - t = t->next; - if (!strcmp(t->string, "(")) - { - brace = qtrue; - t = t->next; - } //end if - if (!t || t->type != TT_NAME) - { - SourceError(source, "defined without name in #if/#elif"); - error = 1; - break; - } //end if - //v = (value_t *) GetClearedMemory(sizeof(value_t)); - AllocValue(v); -#if DEFINEHASHING - if (PC_FindHashedDefine(source->definehash, t->string)) -#else - if (PC_FindDefine(source->defines, t->string)) -#endif //DEFINEHASHING - { - v->intvalue = 1; - v->floatvalue = 1; - } //end if - else - { - v->intvalue = 0; - v->floatvalue = 0; - } //end else - v->parentheses = parentheses; - v->next = NULL; - v->prev = lastvalue; - if (lastvalue) lastvalue->next = v; - else firstvalue = v; - lastvalue = v; - if (brace) - { - t = t->next; - if (!t || strcmp(t->string, ")")) - { - SourceError(source, "defined without ) in #if/#elif"); - error = 1; - break; - } //end if - } //end if - brace = qfalse; - // defined() creates a value - lastwasvalue = 1; - break; - } //end case - case TT_NUMBER: - { - if (lastwasvalue) - { - SourceError(source, "syntax error in #if/#elif"); - error = 1; - break; - } //end if - //v = (value_t *) GetClearedMemory(sizeof(value_t)); - AllocValue(v); - if (negativevalue) - { - v->intvalue = - (signed int) t->intvalue; - v->floatvalue = - t->floatvalue; - } //end if - else - { - v->intvalue = t->intvalue; - v->floatvalue = t->floatvalue; - } //end else - v->parentheses = parentheses; - v->next = NULL; - v->prev = lastvalue; - if (lastvalue) lastvalue->next = v; - else firstvalue = v; - lastvalue = v; - //last token was a value - lastwasvalue = 1; - // - negativevalue = 0; - break; - } //end case - case TT_PUNCTUATION: - { - if (negativevalue) - { - SourceError(source, "misplaced minus sign in #if/#elif"); - error = 1; - break; - } //end if - if (t->subtype == P_PARENTHESESOPEN) - { - parentheses++; - break; - } //end if - else if (t->subtype == P_PARENTHESESCLOSE) - { - parentheses--; - if (parentheses < 0) - { - SourceError(source, "too many ) in #if/#elsif"); - error = 1; - } //end if - break; - } //end else if - //check for invalid operators on floating point values - if (!integer) - { - if (t->subtype == P_BIN_NOT || t->subtype == P_MOD || - t->subtype == P_RSHIFT || t->subtype == P_LSHIFT || - t->subtype == P_BIN_AND || t->subtype == P_BIN_OR || - t->subtype == P_BIN_XOR) - { - SourceError(source, "illigal operator %s on floating point operands\n", t->string); - error = 1; - break; - } //end if - } //end if - switch(t->subtype) - { - case P_LOGIC_NOT: - case P_BIN_NOT: - { - if (lastwasvalue) - { - SourceError(source, "! or ~ after value in #if/#elif"); - error = 1; - break; - } //end if - break; - } //end case - case P_INC: - case P_DEC: - { - SourceError(source, "++ or -- used in #if/#elif"); - break; - } //end case - case P_SUB: - { - if (!lastwasvalue) - { - negativevalue = 1; - break; - } //end if - } //end case - - case P_MUL: - case P_DIV: - case P_MOD: - case P_ADD: - - case P_LOGIC_AND: - case P_LOGIC_OR: - case P_LOGIC_GEQ: - case P_LOGIC_LEQ: - case P_LOGIC_EQ: - case P_LOGIC_UNEQ: - - case P_LOGIC_GREATER: - case P_LOGIC_LESS: - - case P_RSHIFT: - case P_LSHIFT: - - case P_BIN_AND: - case P_BIN_OR: - case P_BIN_XOR: - - case P_COLON: - case P_QUESTIONMARK: - { - if (!lastwasvalue) - { - SourceError(source, "operator %s after operator in #if/#elif", t->string); - error = 1; - break; - } //end if - break; - } //end case - default: - { - SourceError(source, "invalid operator %s in #if/#elif", t->string); - error = 1; - break; - } //end default - } //end switch - if (!error && !negativevalue) - { - //o = (operator_t *) GetClearedMemory(sizeof(operator_t)); - AllocOperator(o); - o->operator = t->subtype; - o->priority = PC_OperatorPriority(t->subtype); - o->parentheses = parentheses; - o->next = NULL; - o->prev = lastoperator; - if (lastoperator) lastoperator->next = o; - else firstoperator = o; - lastoperator = o; - lastwasvalue = 0; - } //end if - break; - } //end case - default: - { - SourceError(source, "unknown %s in #if/#elif", t->string); - error = 1; - break; - } //end default - } //end switch - if (error) break; - } //end for - if (!error) - { - if (!lastwasvalue) - { - SourceError(source, "trailing operator in #if/#elif"); - error = 1; - } //end if - else if (parentheses) - { - SourceError(source, "too many ( in #if/#elif"); - error = 1; - } //end else if - } //end if - // - gotquestmarkvalue = qfalse; - questmarkintvalue = 0; - questmarkfloatvalue = 0; - //while there are operators - while(!error && firstoperator) - { - v = firstvalue; - for (o = firstoperator; o->next; o = o->next) - { - //if the current operator is nested deeper in parentheses - //than the next operator - if (o->parentheses > o->next->parentheses) break; - //if the current and next operator are nested equally deep in parentheses - if (o->parentheses == o->next->parentheses) - { - //if the priority of the current operator is equal or higher - //than the priority of the next operator - if (o->priority >= o->next->priority) break; - } //end if - //if the arity of the operator isn't equal to 1 - if (o->operator != P_LOGIC_NOT - && o->operator != P_BIN_NOT) v = v->next; - //if there's no value or no next value - if (!v) - { - SourceError(source, "mising values in #if/#elif"); - error = 1; - break; - } //end if - } //end for - if (error) break; - v1 = v; - v2 = v->next; -#ifdef DEBUG_EVAL - if (integer) - { - Log_Write("operator %s, value1 = %d", PunctuationFromNum(source->scriptstack, o->operator), v1->intvalue); - if (v2) Log_Write("value2 = %d", v2->intvalue); - } //end if - else - { - Log_Write("operator %s, value1 = %f", PunctuationFromNum(source->scriptstack, o->operator), v1->floatvalue); - if (v2) Log_Write("value2 = %f", v2->floatvalue); - } //end else -#endif //DEBUG_EVAL - switch(o->operator) - { - case P_LOGIC_NOT: v1->intvalue = !v1->intvalue; - v1->floatvalue = !v1->floatvalue; break; - case P_BIN_NOT: v1->intvalue = ~v1->intvalue; - break; - case P_MUL: v1->intvalue *= v2->intvalue; - v1->floatvalue *= v2->floatvalue; break; - case P_DIV: if (!v2->intvalue || !v2->floatvalue) - { - SourceError(source, "divide by zero in #if/#elif\n"); - error = 1; - break; - } - v1->intvalue /= v2->intvalue; - v1->floatvalue /= v2->floatvalue; break; - case P_MOD: if (!v2->intvalue) - { - SourceError(source, "divide by zero in #if/#elif\n"); - error = 1; - break; - } - v1->intvalue %= v2->intvalue; break; - case P_ADD: v1->intvalue += v2->intvalue; - v1->floatvalue += v2->floatvalue; break; - case P_SUB: v1->intvalue -= v2->intvalue; - v1->floatvalue -= v2->floatvalue; break; - case P_LOGIC_AND: v1->intvalue = v1->intvalue && v2->intvalue; - v1->floatvalue = v1->floatvalue && v2->floatvalue; break; - case P_LOGIC_OR: v1->intvalue = v1->intvalue || v2->intvalue; - v1->floatvalue = v1->floatvalue || v2->floatvalue; break; - case P_LOGIC_GEQ: v1->intvalue = v1->intvalue >= v2->intvalue; - v1->floatvalue = v1->floatvalue >= v2->floatvalue; break; - case P_LOGIC_LEQ: v1->intvalue = v1->intvalue <= v2->intvalue; - v1->floatvalue = v1->floatvalue <= v2->floatvalue; break; - case P_LOGIC_EQ: v1->intvalue = v1->intvalue == v2->intvalue; - v1->floatvalue = v1->floatvalue == v2->floatvalue; break; - case P_LOGIC_UNEQ: v1->intvalue = v1->intvalue != v2->intvalue; - v1->floatvalue = v1->floatvalue != v2->floatvalue; break; - case P_LOGIC_GREATER: v1->intvalue = v1->intvalue > v2->intvalue; - v1->floatvalue = v1->floatvalue > v2->floatvalue; break; - case P_LOGIC_LESS: v1->intvalue = v1->intvalue < v2->intvalue; - v1->floatvalue = v1->floatvalue < v2->floatvalue; break; - case P_RSHIFT: v1->intvalue >>= v2->intvalue; - break; - case P_LSHIFT: v1->intvalue <<= v2->intvalue; - break; - case P_BIN_AND: v1->intvalue &= v2->intvalue; - break; - case P_BIN_OR: v1->intvalue |= v2->intvalue; - break; - case P_BIN_XOR: v1->intvalue ^= v2->intvalue; - break; - case P_COLON: - { - if (!gotquestmarkvalue) - { - SourceError(source, ": without ? in #if/#elif"); - error = 1; - break; - } //end if - if (integer) - { - if (!questmarkintvalue) v1->intvalue = v2->intvalue; - } //end if - else - { - if (!questmarkfloatvalue) v1->floatvalue = v2->floatvalue; - } //end else - gotquestmarkvalue = qfalse; - break; - } //end case - case P_QUESTIONMARK: - { - if (gotquestmarkvalue) - { - SourceError(source, "? after ? in #if/#elif"); - error = 1; - break; - } //end if - questmarkintvalue = v1->intvalue; - questmarkfloatvalue = v1->floatvalue; - gotquestmarkvalue = qtrue; - break; - } //end if - } //end switch -#ifdef DEBUG_EVAL - if (integer) Log_Write("result value = %d", v1->intvalue); - else Log_Write("result value = %f", v1->floatvalue); -#endif //DEBUG_EVAL - if (error) break; - lastoperatortype = o->operator; - //if not an operator with arity 1 - if (o->operator != P_LOGIC_NOT - && o->operator != P_BIN_NOT) - { - //remove the second value if not question mark operator - if (o->operator != P_QUESTIONMARK) v = v->next; - // - if (v->prev) v->prev->next = v->next; - else firstvalue = v->next; - if (v->next) v->next->prev = v->prev; - else lastvalue = v->prev; - //FreeMemory(v); - FreeValue(v); - } //end if - //remove the operator - if (o->prev) o->prev->next = o->next; - else firstoperator = o->next; - if (o->next) o->next->prev = o->prev; - else lastoperator = o->prev; - //FreeMemory(o); - FreeOperator(o); - } //end while - if (firstvalue) - { - if (intvalue) *intvalue = firstvalue->intvalue; - if (floatvalue) *floatvalue = firstvalue->floatvalue; - } //end if - for (o = firstoperator; o; o = lastoperator) - { - lastoperator = o->next; - //FreeMemory(o); - FreeOperator(o); - } //end for - for (v = firstvalue; v; v = lastvalue) - { - lastvalue = v->next; - //FreeMemory(v); - FreeValue(v); - } //end for - if (!error) return qtrue; - if (intvalue) *intvalue = 0; - if (floatvalue) *floatvalue = 0; - return qfalse; -} //end of the function PC_EvaluateTokens -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_Evaluate(source_t *source, signed long int *intvalue, - double *floatvalue, int integer) -{ - token_t token, *firsttoken, *lasttoken; - token_t *t, *nexttoken; - define_t *define; - int defined = qfalse; - - if (intvalue) *intvalue = 0; - if (floatvalue) *floatvalue = 0; - // - if (!PC_ReadLine(source, &token)) - { - SourceError(source, "no value after #if/#elif"); - return qfalse; - } //end if - firsttoken = NULL; - lasttoken = NULL; - do - { - //if the token is a name - if (token.type == TT_NAME) - { - if (defined) - { - defined = qfalse; - t = PC_CopyToken(&token); - t->next = NULL; - if (lasttoken) lasttoken->next = t; - else firsttoken = t; - lasttoken = t; - } //end if - else if (!strcmp(token.string, "defined")) - { - defined = qtrue; - t = PC_CopyToken(&token); - t->next = NULL; - if (lasttoken) lasttoken->next = t; - else firsttoken = t; - lasttoken = t; - } //end if - else - { - //then it must be a define -#if DEFINEHASHING - define = PC_FindHashedDefine(source->definehash, token.string); -#else - define = PC_FindDefine(source->defines, token.string); -#endif //DEFINEHASHING - if (!define) - { - SourceError(source, "can't evaluate %s, not defined", token.string); - return qfalse; - } //end if - if (!PC_ExpandDefineIntoSource(source, &token, define)) return qfalse; - } //end else - } //end if - //if the token is a number or a punctuation - else if (token.type == TT_NUMBER || token.type == TT_PUNCTUATION) - { - t = PC_CopyToken(&token); - t->next = NULL; - if (lasttoken) lasttoken->next = t; - else firsttoken = t; - lasttoken = t; - } //end else - else //can't evaluate the token - { - SourceError(source, "can't evaluate %s", token.string); - return qfalse; - } //end else - } while(PC_ReadLine(source, &token)); - // - if (!PC_EvaluateTokens(source, firsttoken, intvalue, floatvalue, integer)) return qfalse; - // -#ifdef DEBUG_EVAL - Log_Write("eval:"); -#endif //DEBUG_EVAL - for (t = firsttoken; t; t = nexttoken) - { -#ifdef DEBUG_EVAL - Log_Write(" %s", t->string); -#endif //DEBUG_EVAL - nexttoken = t->next; - PC_FreeToken(t); - } //end for -#ifdef DEBUG_EVAL - if (integer) Log_Write("eval result: %d", *intvalue); - else Log_Write("eval result: %f", *floatvalue); -#endif //DEBUG_EVAL - // - return qtrue; -} //end of the function PC_Evaluate -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_DollarEvaluate(source_t *source, signed long int *intvalue, - double *floatvalue, int integer) -{ - int indent, defined = qfalse; - token_t token, *firsttoken, *lasttoken; - token_t *t, *nexttoken; - define_t *define; - - if (intvalue) *intvalue = 0; - if (floatvalue) *floatvalue = 0; - // - if (!PC_ReadSourceToken(source, &token)) - { - SourceError(source, "no leading ( after $evalint/$evalfloat"); - return qfalse; - } //end if - if (!PC_ReadSourceToken(source, &token)) - { - SourceError(source, "nothing to evaluate"); - return qfalse; - } //end if - indent = 1; - firsttoken = NULL; - lasttoken = NULL; - do - { - //if the token is a name - if (token.type == TT_NAME) - { - if (defined) - { - defined = qfalse; - t = PC_CopyToken(&token); - t->next = NULL; - if (lasttoken) lasttoken->next = t; - else firsttoken = t; - lasttoken = t; - } //end if - else if (!strcmp(token.string, "defined")) - { - defined = qtrue; - t = PC_CopyToken(&token); - t->next = NULL; - if (lasttoken) lasttoken->next = t; - else firsttoken = t; - lasttoken = t; - } //end if - else - { - //then it must be a define -#if DEFINEHASHING - define = PC_FindHashedDefine(source->definehash, token.string); -#else - define = PC_FindDefine(source->defines, token.string); -#endif //DEFINEHASHING - if (!define) - { - SourceError(source, "can't evaluate %s, not defined", token.string); - return qfalse; - } //end if - if (!PC_ExpandDefineIntoSource(source, &token, define)) return qfalse; - } //end else - } //end if - //if the token is a number or a punctuation - else if (token.type == TT_NUMBER || token.type == TT_PUNCTUATION) - { - if (*token.string == '(') indent++; - else if (*token.string == ')') indent--; - if (indent <= 0) break; - t = PC_CopyToken(&token); - t->next = NULL; - if (lasttoken) lasttoken->next = t; - else firsttoken = t; - lasttoken = t; - } //end else - else //can't evaluate the token - { - SourceError(source, "can't evaluate %s", token.string); - return qfalse; - } //end else - } while(PC_ReadSourceToken(source, &token)); - // - if (!PC_EvaluateTokens(source, firsttoken, intvalue, floatvalue, integer)) return qfalse; - // -#ifdef DEBUG_EVAL - Log_Write("$eval:"); -#endif //DEBUG_EVAL - for (t = firsttoken; t; t = nexttoken) - { -#ifdef DEBUG_EVAL - Log_Write(" %s", t->string); -#endif //DEBUG_EVAL - nexttoken = t->next; - PC_FreeToken(t); - } //end for -#ifdef DEBUG_EVAL - if (integer) Log_Write("$eval result: %d", *intvalue); - else Log_Write("$eval result: %f", *floatvalue); -#endif //DEBUG_EVAL - // - return qtrue; -} //end of the function PC_DollarEvaluate -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_Directive_elif(source_t *source) -{ - signed long int value; - int type, skip; - - PC_PopIndent(source, &type, &skip); - if (!type || type == INDENT_ELSE) - { - SourceError(source, "misplaced #elif"); - return qfalse; - } //end if - if (!PC_Evaluate(source, &value, NULL, qtrue)) return qfalse; - skip = (value == 0); - PC_PushIndent(source, INDENT_ELIF, skip); - return qtrue; -} //end of the function PC_Directive_elif -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_Directive_if(source_t *source) -{ - signed long int value; - int skip; - - if (!PC_Evaluate(source, &value, NULL, qtrue)) return qfalse; - skip = (value == 0); - PC_PushIndent(source, INDENT_IF, skip); - return qtrue; -} //end of the function PC_Directive -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_Directive_line(source_t *source) -{ - SourceError(source, "#line directive not supported"); - return qfalse; -} //end of the function PC_Directive_line -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_Directive_error(source_t *source) -{ - token_t token; - - strcpy(token.string, ""); - PC_ReadSourceToken(source, &token); - SourceError(source, "#error directive: %s", token.string); - return qfalse; -} //end of the function PC_Directive_error -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_Directive_pragma(source_t *source) -{ - token_t token; - - SourceWarning(source, "#pragma directive not supported"); - while(PC_ReadLine(source, &token)) ; - return qtrue; -} //end of the function PC_Directive_pragma -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void UnreadSignToken(source_t *source) -{ - token_t token; - - token.line = source->scriptstack->line; - token.whitespace_p = source->scriptstack->script_p; - token.endwhitespace_p = source->scriptstack->script_p; - token.linescrossed = 0; - strcpy(token.string, "-"); - token.type = TT_PUNCTUATION; - token.subtype = P_SUB; - PC_UnreadSourceToken(source, &token); -} //end of the function UnreadSignToken -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_Directive_eval(source_t *source) -{ - signed long int value; - token_t token; - - if (!PC_Evaluate(source, &value, NULL, qtrue)) return qfalse; - // - token.line = source->scriptstack->line; - token.whitespace_p = source->scriptstack->script_p; - token.endwhitespace_p = source->scriptstack->script_p; - token.linescrossed = 0; - sprintf(token.string, "%d", abs(value)); - token.type = TT_NUMBER; - token.subtype = TT_INTEGER|TT_LONG|TT_DECIMAL; - PC_UnreadSourceToken(source, &token); - if (value < 0) UnreadSignToken(source); - return qtrue; -} //end of the function PC_Directive_eval -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_Directive_evalfloat(source_t *source) -{ - double value; - token_t token; - - if (!PC_Evaluate(source, NULL, &value, qfalse)) return qfalse; - token.line = source->scriptstack->line; - token.whitespace_p = source->scriptstack->script_p; - token.endwhitespace_p = source->scriptstack->script_p; - token.linescrossed = 0; - sprintf(token.string, "%1.2f", fabs(value)); - token.type = TT_NUMBER; - token.subtype = TT_FLOAT|TT_LONG|TT_DECIMAL; - PC_UnreadSourceToken(source, &token); - if (value < 0) UnreadSignToken(source); - return qtrue; -} //end of the function PC_Directive_evalfloat -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -directive_t directives[20] = -{ - {"if", PC_Directive_if}, - {"ifdef", PC_Directive_ifdef}, - {"ifndef", PC_Directive_ifndef}, - {"elif", PC_Directive_elif}, - {"else", PC_Directive_else}, - {"endif", PC_Directive_endif}, - {"include", PC_Directive_include}, - {"define", PC_Directive_define}, - {"undef", PC_Directive_undef}, - {"line", PC_Directive_line}, - {"error", PC_Directive_error}, - {"pragma", PC_Directive_pragma}, - {"eval", PC_Directive_eval}, - {"evalfloat", PC_Directive_evalfloat}, - {NULL, NULL} -}; - -int PC_ReadDirective(source_t *source) -{ - token_t token; - int i; - - //read the directive name - if (!PC_ReadSourceToken(source, &token)) - { - SourceError(source, "found # without name"); - return qfalse; - } //end if - //directive name must be on the same line - if (token.linescrossed > 0) - { - PC_UnreadSourceToken(source, &token); - SourceError(source, "found # at end of line"); - return qfalse; - } //end if - //if if is a name - if (token.type == TT_NAME) - { - //find the precompiler directive - for (i = 0; directives[i].name; i++) - { - if (!strcmp(directives[i].name, token.string)) - { - return directives[i].func(source); - } //end if - } //end for - } //end if - SourceError(source, "unknown precompiler directive %s", token.string); - return qfalse; -} //end of the function PC_ReadDirective -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_DollarDirective_evalint(source_t *source) -{ - signed long int value; - token_t token; - - if (!PC_DollarEvaluate(source, &value, NULL, qtrue)) return qfalse; - // - token.line = source->scriptstack->line; - token.whitespace_p = source->scriptstack->script_p; - token.endwhitespace_p = source->scriptstack->script_p; - token.linescrossed = 0; - sprintf(token.string, "%d", abs(value)); - token.type = TT_NUMBER; - token.subtype = TT_INTEGER|TT_LONG|TT_DECIMAL; -#ifdef NUMBERVALUE - token.intvalue = value; - token.floatvalue = value; -#endif //NUMBERVALUE - PC_UnreadSourceToken(source, &token); - if (value < 0) UnreadSignToken(source); - return qtrue; -} //end of the function PC_DollarDirective_evalint -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_DollarDirective_evalfloat(source_t *source) -{ - double value; - token_t token; - - if (!PC_DollarEvaluate(source, NULL, &value, qfalse)) return qfalse; - token.line = source->scriptstack->line; - token.whitespace_p = source->scriptstack->script_p; - token.endwhitespace_p = source->scriptstack->script_p; - token.linescrossed = 0; - sprintf(token.string, "%1.2f", fabs(value)); - token.type = TT_NUMBER; - token.subtype = TT_FLOAT|TT_LONG|TT_DECIMAL; -#ifdef NUMBERVALUE - token.intvalue = (unsigned long) value; - token.floatvalue = value; -#endif //NUMBERVALUE - PC_UnreadSourceToken(source, &token); - if (value < 0) UnreadSignToken(source); - return qtrue; -} //end of the function PC_DollarDirective_evalfloat -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -directive_t dollardirectives[20] = -{ - {"evalint", PC_DollarDirective_evalint}, - {"evalfloat", PC_DollarDirective_evalfloat}, - {NULL, NULL} -}; - -int PC_ReadDollarDirective(source_t *source) -{ - token_t token; - int i; - - //read the directive name - if (!PC_ReadSourceToken(source, &token)) - { - SourceError(source, "found $ without name"); - return qfalse; - } //end if - //directive name must be on the same line - if (token.linescrossed > 0) - { - PC_UnreadSourceToken(source, &token); - SourceError(source, "found $ at end of line"); - return qfalse; - } //end if - //if if is a name - if (token.type == TT_NAME) - { - //find the precompiler directive - for (i = 0; dollardirectives[i].name; i++) - { - if (!strcmp(dollardirectives[i].name, token.string)) - { - return dollardirectives[i].func(source); - } //end if - } //end for - } //end if - PC_UnreadSourceToken(source, &token); - SourceError(source, "unknown precompiler directive %s", token.string); - return qfalse; -} //end of the function PC_ReadDirective - -#ifdef QUAKEC -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int BuiltinFunction(source_t *source) -{ - token_t token; - - if (!PC_ReadSourceToken(source, &token)) return qfalse; - if (token.type == TT_NUMBER) - { - PC_UnreadSourceToken(source, &token); - return qtrue; - } //end if - else - { - PC_UnreadSourceToken(source, &token); - return qfalse; - } //end else -} //end of the function BuiltinFunction -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int QuakeCMacro(source_t *source) -{ - int i; - token_t token; - - if (!PC_ReadSourceToken(source, &token)) return qtrue; - if (token.type != TT_NAME) - { - PC_UnreadSourceToken(source, &token); - return qtrue; - } //end if - //find the precompiler directive - for (i = 0; dollardirectives[i].name; i++) - { - if (!strcmp(dollardirectives[i].name, token.string)) - { - PC_UnreadSourceToken(source, &token); - return qfalse; - } //end if - } //end for - PC_UnreadSourceToken(source, &token); - return qtrue; -} //end of the function QuakeCMacro -#endif //QUAKEC -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_ReadToken(source_t *source, token_t *token) -{ - define_t *define; - - while(1) - { - if (!PC_ReadSourceToken(source, token)) return qfalse; - //check for precompiler directives - if (token->type == TT_PUNCTUATION && *token->string == '#') - { -#ifdef QUAKEC - if (!BuiltinFunction(source)) -#endif //QUAKC - { - //read the precompiler directive - if (!PC_ReadDirective(source)) return qfalse; - continue; - } //end if - } //end if - if (token->type == TT_PUNCTUATION && *token->string == '$') - { -#ifdef QUAKEC - if (!QuakeCMacro(source)) -#endif //QUAKEC - { - //read the precompiler directive - if (!PC_ReadDollarDirective(source)) return qfalse; - continue; - } //end if - } //end if - // recursively concatenate strings that are behind each other still resolving defines - if (token->type == TT_STRING) - { - token_t newtoken; - if (PC_ReadToken(source, &newtoken)) - { - if (newtoken.type == TT_STRING) - { - token->string[strlen(token->string)-1] = '\0'; - if (strlen(token->string) + strlen(newtoken.string+1) + 1 >= MAX_TOKEN) - { - SourceError(source, "string longer than MAX_TOKEN %d\n", MAX_TOKEN); - return qfalse; - } - strcat(token->string, newtoken.string+1); - } - else - { - PC_UnreadToken(source, &newtoken); - } - } - } //end if - //if skipping source because of conditional compilation - if (source->skip) continue; - //if the token is a name - if (token->type == TT_NAME) - { - //check if the name is a define macro -#if DEFINEHASHING - define = PC_FindHashedDefine(source->definehash, token->string); -#else - define = PC_FindDefine(source->defines, token->string); -#endif //DEFINEHASHING - //if it is a define macro - if (define) - { - //expand the defined macro - if (!PC_ExpandDefineIntoSource(source, token, define)) return qfalse; - continue; - } //end if - } //end if - //copy token for unreading - Com_Memcpy(&source->token, token, sizeof(token_t)); - //found a token - return qtrue; - } //end while -} //end of the function PC_ReadToken -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_ExpectTokenString(source_t *source, char *string) -{ - token_t token; - - if (!PC_ReadToken(source, &token)) - { - SourceError(source, "couldn't find expected %s", string); - return qfalse; - } //end if - - if (strcmp(token.string, string)) - { - SourceError(source, "expected %s, found %s", string, token.string); - return qfalse; - } //end if - return qtrue; -} //end of the function PC_ExpectTokenString -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_ExpectTokenType(source_t *source, int type, int subtype, token_t *token) -{ - char str[MAX_TOKEN]; - - if (!PC_ReadToken(source, token)) - { - SourceError(source, "couldn't read expected token"); - return qfalse; - } //end if - - if (token->type != type) - { - strcpy(str, ""); - if (type == TT_STRING) strcpy(str, "string"); - if (type == TT_LITERAL) strcpy(str, "literal"); - if (type == TT_NUMBER) strcpy(str, "number"); - if (type == TT_NAME) strcpy(str, "name"); - if (type == TT_PUNCTUATION) strcpy(str, "punctuation"); - SourceError(source, "expected a %s, found %s", str, token->string); - return qfalse; - } //end if - if (token->type == TT_NUMBER) - { - if ((token->subtype & subtype) != subtype) - { - if (subtype & TT_DECIMAL) strcpy(str, "decimal"); - if (subtype & TT_HEX) strcpy(str, "hex"); - if (subtype & TT_OCTAL) strcpy(str, "octal"); - if (subtype & TT_BINARY) strcpy(str, "binary"); - if (subtype & TT_LONG) strcat(str, " long"); - if (subtype & TT_UNSIGNED) strcat(str, " unsigned"); - if (subtype & TT_FLOAT) strcat(str, " float"); - if (subtype & TT_INTEGER) strcat(str, " integer"); - SourceError(source, "expected %s, found %s", str, token->string); - return qfalse; - } //end if - } //end if - else if (token->type == TT_PUNCTUATION) - { - if (token->subtype != subtype) - { - SourceError(source, "found %s", token->string); - return qfalse; - } //end if - } //end else if - return qtrue; -} //end of the function PC_ExpectTokenType -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_ExpectAnyToken(source_t *source, token_t *token) -{ - if (!PC_ReadToken(source, token)) - { - SourceError(source, "couldn't read expected token"); - return qfalse; - } //end if - else - { - return qtrue; - } //end else -} //end of the function PC_ExpectAnyToken -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_CheckTokenString(source_t *source, char *string) -{ - token_t tok; - - if (!PC_ReadToken(source, &tok)) return qfalse; - //if the token is available - if (!strcmp(tok.string, string)) return qtrue; - // - PC_UnreadSourceToken(source, &tok); - return qfalse; -} //end of the function PC_CheckTokenString -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_CheckTokenType(source_t *source, int type, int subtype, token_t *token) -{ - token_t tok; - - if (!PC_ReadToken(source, &tok)) return qfalse; - //if the type matches - if (tok.type == type && - (tok.subtype & subtype) == subtype) - { - Com_Memcpy(token, &tok, sizeof(token_t)); - return qtrue; - } //end if - // - PC_UnreadSourceToken(source, &tok); - return qfalse; -} //end of the function PC_CheckTokenType -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_SkipUntilString(source_t *source, char *string) -{ - token_t token; - - while(PC_ReadToken(source, &token)) - { - if (!strcmp(token.string, string)) return qtrue; - } //end while - return qfalse; -} //end of the function PC_SkipUntilString -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_UnreadLastToken(source_t *source) -{ - PC_UnreadSourceToken(source, &source->token); -} //end of the function PC_UnreadLastToken -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_UnreadToken(source_t *source, token_t *token) -{ - PC_UnreadSourceToken(source, token); -} //end of the function PC_UnreadToken -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_SetIncludePath(source_t *source, char *path) -{ - strncpy(source->includepath, path, MAX_PATH); - //add trailing path seperator - if (source->includepath[strlen(source->includepath)-1] != '\\' && - source->includepath[strlen(source->includepath)-1] != '/') - { - strcat(source->includepath, PATHSEPERATOR_STR); - } //end if -} //end of the function PC_SetIncludePath -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_SetPunctuations(source_t *source, punctuation_t *p) -{ - source->punctuations = p; -} //end of the function PC_SetPunctuations -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -source_t *LoadSourceFile(const char *filename) -{ - source_t *source; - script_t *script; - - PC_InitTokenHeap(); - - script = LoadScriptFile(filename); - if (!script) return NULL; - - script->next = NULL; - - source = (source_t *) GetMemory(sizeof(source_t)); - Com_Memset(source, 0, sizeof(source_t)); - - strncpy(source->filename, filename, MAX_PATH); - source->scriptstack = script; - source->tokens = NULL; - source->defines = NULL; - source->indentstack = NULL; - source->skip = 0; - -#if DEFINEHASHING - source->definehash = GetClearedMemory(DEFINEHASHSIZE * sizeof(define_t *)); -#endif //DEFINEHASHING - PC_AddGlobalDefinesToSource(source); - return source; -} //end of the function LoadSourceFile -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -source_t *LoadSourceMemory(char *ptr, int length, char *name) -{ - source_t *source; - script_t *script; - - PC_InitTokenHeap(); - - script = LoadScriptMemory(ptr, length, name); - if (!script) return NULL; - script->next = NULL; - - source = (source_t *) GetMemory(sizeof(source_t)); - Com_Memset(source, 0, sizeof(source_t)); - - strncpy(source->filename, name, MAX_PATH); - source->scriptstack = script; - source->tokens = NULL; - source->defines = NULL; - source->indentstack = NULL; - source->skip = 0; - -#if DEFINEHASHING - source->definehash = GetClearedMemory(DEFINEHASHSIZE * sizeof(define_t *)); -#endif //DEFINEHASHING - PC_AddGlobalDefinesToSource(source); - return source; -} //end of the function LoadSourceMemory -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void FreeSource(source_t *source) -{ - script_t *script; - token_t *token; - define_t *define; - indent_t *indent; - int i; - - //PC_PrintDefineHashTable(source->definehash); - //free all the scripts - while(source->scriptstack) - { - script = source->scriptstack; - source->scriptstack = source->scriptstack->next; - FreeScript(script); - } //end for - //free all the tokens - while(source->tokens) - { - token = source->tokens; - source->tokens = source->tokens->next; - PC_FreeToken(token); - } //end for -#if DEFINEHASHING - for (i = 0; i < DEFINEHASHSIZE; i++) - { - while(source->definehash[i]) - { - define = source->definehash[i]; - source->definehash[i] = source->definehash[i]->hashnext; - PC_FreeDefine(define); - } //end while - } //end for -#else //DEFINEHASHING - //free all defines - while(source->defines) - { - define = source->defines; - source->defines = source->defines->next; - PC_FreeDefine(define); - } //end for -#endif //DEFINEHASHING - //free all indents - while(source->indentstack) - { - indent = source->indentstack; - source->indentstack = source->indentstack->next; - FreeMemory(indent); - } //end for -#if DEFINEHASHING - // - if (source->definehash) FreeMemory(source->definehash); -#endif //DEFINEHASHING - //free the source itself - FreeMemory(source); -} //end of the function FreeSource -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ - -#define MAX_SOURCEFILES 64 - -source_t *sourceFiles[MAX_SOURCEFILES]; - -int PC_LoadSourceHandle(const char *filename) -{ - source_t *source; - int i; - - for (i = 1; i < MAX_SOURCEFILES; i++) - { - if (!sourceFiles[i]) - break; - } //end for - if (i >= MAX_SOURCEFILES) - return 0; - PS_SetBaseFolder(""); - source = LoadSourceFile(filename); - if (!source) - return 0; - sourceFiles[i] = source; - return i; -} //end of the function PC_LoadSourceHandle -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_FreeSourceHandle(int handle) -{ - if (handle < 1 || handle >= MAX_SOURCEFILES) - return qfalse; - if (!sourceFiles[handle]) - return qfalse; - - FreeSource(sourceFiles[handle]); - sourceFiles[handle] = NULL; - return qtrue; -} //end of the function PC_FreeSourceHandle -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_ReadTokenHandle(int handle, pc_token_t *pc_token) -{ - token_t token; - int ret; - - if (handle < 1 || handle >= MAX_SOURCEFILES) - return 0; - if (!sourceFiles[handle]) - return 0; - - ret = PC_ReadToken(sourceFiles[handle], &token); - strcpy(pc_token->string, token.string); - pc_token->type = token.type; - pc_token->subtype = token.subtype; - pc_token->intvalue = token.intvalue; - pc_token->floatvalue = token.floatvalue; - if (pc_token->type == TT_STRING) - StripDoubleQuotes(pc_token->string); - return ret; -} //end of the function PC_ReadTokenHandle -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PC_SourceFileAndLine(int handle, char *filename, int *line) -{ - if (handle < 1 || handle >= MAX_SOURCEFILES) - return qfalse; - if (!sourceFiles[handle]) - return qfalse; - - strcpy(filename, sourceFiles[handle]->filename); - if (sourceFiles[handle]->scriptstack) - *line = sourceFiles[handle]->scriptstack->line; - else - *line = 0; - return qtrue; -} //end of the function PC_SourceFileAndLine -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_SetBaseFolder(char *path) -{ - PS_SetBaseFolder(path); -} //end of the function PC_SetBaseFolder -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PC_CheckOpenSourceHandles(void) -{ - int i; - - for (i = 1; i < MAX_SOURCEFILES; i++) - { - if (sourceFiles[i]) - { -#ifdef BOTLIB - botimport.Print(PRT_ERROR, "file %s still open in precompiler\n", sourceFiles[i]->scriptstack->filename); -#endif //BOTLIB - } //end if - } //end for -} //end of the function PC_CheckOpenSourceHandles - diff --git a/src/botlib/l_precomp.h b/src/botlib/l_precomp.h deleted file mode 100644 index b61125bf..00000000 --- a/src/botlib/l_precomp.h +++ /dev/null @@ -1,181 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: l_precomp.h - * - * desc: pre compiler - * - * $Archive: /source/code/botlib/l_precomp.h $ - * - *****************************************************************************/ - -#ifndef MAX_PATH - #define MAX_PATH MAX_QPATH -#endif - -#ifndef PATH_SEPERATORSTR - #if defined(WIN32)|defined(_WIN32)|defined(__NT__)|defined(__WINDOWS__)|defined(__WINDOWS_386__) - #define PATHSEPERATOR_STR "\\" - #else - #define PATHSEPERATOR_STR "/" - #endif -#endif -#ifndef PATH_SEPERATORCHAR - #if defined(WIN32)|defined(_WIN32)|defined(__NT__)|defined(__WINDOWS__)|defined(__WINDOWS_386__) - #define PATHSEPERATOR_CHAR '\\' - #else - #define PATHSEPERATOR_CHAR '/' - #endif -#endif - -#if defined(BSPC) && !defined(QDECL) -#define QDECL -#endif - - -#define DEFINE_FIXED 0x0001 - -#define BUILTIN_LINE 1 -#define BUILTIN_FILE 2 -#define BUILTIN_DATE 3 -#define BUILTIN_TIME 4 -#define BUILTIN_STDC 5 - -#define INDENT_IF 0x0001 -#define INDENT_ELSE 0x0002 -#define INDENT_ELIF 0x0004 -#define INDENT_IFDEF 0x0008 -#define INDENT_IFNDEF 0x0010 - -//macro definitions -typedef struct define_s -{ - char *name; //define name - int flags; //define flags - int builtin; // > 0 if builtin define - int numparms; //number of define parameters - token_t *parms; //define parameters - token_t *tokens; //macro tokens (possibly containing parm tokens) - struct define_s *next; //next defined macro in a list - struct define_s *hashnext; //next define in the hash chain -} define_t; - -//indents -//used for conditional compilation directives: -//#if, #else, #elif, #ifdef, #ifndef -typedef struct indent_s -{ - int type; //indent type - int skip; //true if skipping current indent - script_t *script; //script the indent was in - struct indent_s *next; //next indent on the indent stack -} indent_t; - -//source file -typedef struct source_s -{ - char filename[1024]; //file name of the script - char includepath[1024]; //path to include files - punctuation_t *punctuations; //punctuations to use - script_t *scriptstack; //stack with scripts of the source - token_t *tokens; //tokens to read first - define_t *defines; //list with macro definitions - define_t **definehash; //hash chain with defines - indent_t *indentstack; //stack with indents - int skip; // > 0 if skipping conditional code - token_t token; //last read token -} source_t; - - -//read a token from the source -int PC_ReadToken(source_t *source, token_t *token); -//expect a certain token -int PC_ExpectTokenString(source_t *source, char *string); -//expect a certain token type -int PC_ExpectTokenType(source_t *source, int type, int subtype, token_t *token); -//expect a token -int PC_ExpectAnyToken(source_t *source, token_t *token); -//returns true when the token is available -int PC_CheckTokenString(source_t *source, char *string); -//returns true an reads the token when a token with the given type is available -int PC_CheckTokenType(source_t *source, int type, int subtype, token_t *token); -//skip tokens until the given token string is read -int PC_SkipUntilString(source_t *source, char *string); -//unread the last token read from the script -void PC_UnreadLastToken(source_t *source); -//unread the given token -void PC_UnreadToken(source_t *source, token_t *token); -//read a token only if on the same line, lines are concatenated with a slash -int PC_ReadLine(source_t *source, token_t *token); -//returns true if there was a white space in front of the token -int PC_WhiteSpaceBeforeToken(token_t *token); -//add a define to the source -int PC_AddDefine(source_t *source, char *string); -//add a globals define that will be added to all opened sources -int PC_AddGlobalDefine(char *string); -//remove the given global define -int PC_RemoveGlobalDefine(char *name); -//remove all globals defines -void PC_RemoveAllGlobalDefines(void); -//add builtin defines -void PC_AddBuiltinDefines(source_t *source); -//set the source include path -void PC_SetIncludePath(source_t *source, char *path); -//set the punction set -void PC_SetPunctuations(source_t *source, punctuation_t *p); -//set the base folder to load files from -void PC_SetBaseFolder(char *path); -//load a source file -source_t *LoadSourceFile(const char *filename); -//load a source from memory -source_t *LoadSourceMemory(char *ptr, int length, char *name); -//free the given source -void FreeSource(source_t *source); -//print a source error -void QDECL SourceError(source_t *source, char *str, ...); -//print a source warning -void QDECL SourceWarning(source_t *source, char *str, ...); - -#ifdef BSPC -// some of BSPC source does include game/q_shared.h and some does not -// we define pc_token_s pc_token_t if needed (yes, it's ugly) -#ifndef __Q_SHARED_H -#define MAX_TOKENLENGTH 1024 -typedef struct pc_token_s -{ - int type; - int subtype; - int intvalue; - float floatvalue; - char string[MAX_TOKENLENGTH]; -} pc_token_t; -#endif //!_Q_SHARED_H -#endif //BSPC - -// -int PC_LoadSourceHandle(const char *filename); -int PC_FreeSourceHandle(int handle); -int PC_ReadTokenHandle(int handle, pc_token_t *pc_token); -int PC_SourceFileAndLine(int handle, char *filename, int *line); -void PC_CheckOpenSourceHandles(void); diff --git a/src/botlib/l_script.c b/src/botlib/l_script.c deleted file mode 100644 index 485254fe..00000000 --- a/src/botlib/l_script.c +++ /dev/null @@ -1,1434 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: l_script.c - * - * desc: lexicographical parser - * - * $Archive: /MissionPack/code/botlib/l_script.c $ - * - *****************************************************************************/ - -//#define SCREWUP -//#define BOTLIB -//#define MEQCC -//#define BSPC - -#ifdef SCREWUP -#include <stdio.h> -#include <stdlib.h> -#include <limits.h> -#include <string.h> -#include <stdarg.h> -#include "l_memory.h" -#include "l_script.h" - -typedef enum {qfalse, qtrue} qboolean; - -#endif //SCREWUP - -#ifdef BOTLIB -//include files for usage in the bot library -#include "../qcommon/q_shared.h" -#include "botlib.h" -#include "be_interface.h" -#include "l_script.h" -#include "l_memory.h" -#include "l_log.h" -#include "l_libvar.h" -#endif //BOTLIB - -#ifdef MEQCC -//include files for usage in MrElusive's QuakeC Compiler -#include "qcc.h" -#include "l_script.h" -#include "l_memory.h" -#include "l_log.h" - -#define qtrue true -#define qfalse false -#endif //MEQCC - -#ifdef BSPC -//include files for usage in the BSP Converter -#include "../bspc/qbsp.h" -#include "../bspc/l_log.h" -#include "../bspc/l_mem.h" - -#define qtrue true -#define qfalse false -#endif //BSPC - - -#define PUNCTABLE - -//longer punctuations first -punctuation_t default_punctuations[] = -{ - //binary operators - {">>=",P_RSHIFT_ASSIGN, NULL}, - {"<<=",P_LSHIFT_ASSIGN, NULL}, - // - {"...",P_PARMS, NULL}, - //define merge operator - {"##",P_PRECOMPMERGE, NULL}, - //logic operators - {"&&",P_LOGIC_AND, NULL}, - {"||",P_LOGIC_OR, NULL}, - {">=",P_LOGIC_GEQ, NULL}, - {"<=",P_LOGIC_LEQ, NULL}, - {"==",P_LOGIC_EQ, NULL}, - {"!=",P_LOGIC_UNEQ, NULL}, - //arithmatic operators - {"*=",P_MUL_ASSIGN, NULL}, - {"/=",P_DIV_ASSIGN, NULL}, - {"%=",P_MOD_ASSIGN, NULL}, - {"+=",P_ADD_ASSIGN, NULL}, - {"-=",P_SUB_ASSIGN, NULL}, - {"++",P_INC, NULL}, - {"--",P_DEC, NULL}, - //binary operators - {"&=",P_BIN_AND_ASSIGN, NULL}, - {"|=",P_BIN_OR_ASSIGN, NULL}, - {"^=",P_BIN_XOR_ASSIGN, NULL}, - {">>",P_RSHIFT, NULL}, - {"<<",P_LSHIFT, NULL}, - //reference operators - {"->",P_POINTERREF, NULL}, - //C++ - {"::",P_CPP1, NULL}, - {".*",P_CPP2, NULL}, - //arithmatic operators - {"*",P_MUL, NULL}, - {"/",P_DIV, NULL}, - {"%",P_MOD, NULL}, - {"+",P_ADD, NULL}, - {"-",P_SUB, NULL}, - {"=",P_ASSIGN, NULL}, - //binary operators - {"&",P_BIN_AND, NULL}, - {"|",P_BIN_OR, NULL}, - {"^",P_BIN_XOR, NULL}, - {"~",P_BIN_NOT, NULL}, - //logic operators - {"!",P_LOGIC_NOT, NULL}, - {">",P_LOGIC_GREATER, NULL}, - {"<",P_LOGIC_LESS, NULL}, - //reference operator - {".",P_REF, NULL}, - //seperators - {",",P_COMMA, NULL}, - {";",P_SEMICOLON, NULL}, - //label indication - {":",P_COLON, NULL}, - //if statement - {"?",P_QUESTIONMARK, NULL}, - //embracements - {"(",P_PARENTHESESOPEN, NULL}, - {")",P_PARENTHESESCLOSE, NULL}, - {"{",P_BRACEOPEN, NULL}, - {"}",P_BRACECLOSE, NULL}, - {"[",P_SQBRACKETOPEN, NULL}, - {"]",P_SQBRACKETCLOSE, NULL}, - // - {"\\",P_BACKSLASH, NULL}, - //precompiler operator - {"#",P_PRECOMP, NULL}, -#ifdef DOLLAR - {"$",P_DOLLAR, NULL}, -#endif //DOLLAR - {NULL, 0} -}; - -#ifdef BSPC -char basefolder[MAX_PATH]; -#else -char basefolder[MAX_QPATH]; -#endif - -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void PS_CreatePunctuationTable(script_t *script, punctuation_t *punctuations) -{ - int i; - punctuation_t *p, *lastp, *newp; - - //get memory for the table - if (!script->punctuationtable) script->punctuationtable = (punctuation_t **) - GetMemory(256 * sizeof(punctuation_t *)); - Com_Memset(script->punctuationtable, 0, 256 * sizeof(punctuation_t *)); - //add the punctuations in the list to the punctuation table - for (i = 0; punctuations[i].p; i++) - { - newp = &punctuations[i]; - lastp = NULL; - //sort the punctuations in this table entry on length (longer punctuations first) - for (p = script->punctuationtable[(unsigned int) newp->p[0]]; p; p = p->next) - { - if (strlen(p->p) < strlen(newp->p)) - { - newp->next = p; - if (lastp) lastp->next = newp; - else script->punctuationtable[(unsigned int) newp->p[0]] = newp; - break; - } //end if - lastp = p; - } //end for - if (!p) - { - newp->next = NULL; - if (lastp) lastp->next = newp; - else script->punctuationtable[(unsigned int) newp->p[0]] = newp; - } //end if - } //end for -} //end of the function PS_CreatePunctuationTable -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -char *PunctuationFromNum(script_t *script, int num) -{ - int i; - - for (i = 0; script->punctuations[i].p; i++) - { - if (script->punctuations[i].n == num) return script->punctuations[i].p; - } //end for - return "unkown punctuation"; -} //end of the function PunctuationFromNum -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void QDECL ScriptError(script_t *script, char *str, ...) -{ - char text[1024]; - va_list ap; - - if (script->flags & SCFL_NOERRORS) return; - - va_start(ap, str); - vsprintf(text, str, ap); - va_end(ap); -#ifdef BOTLIB - botimport.Print(PRT_ERROR, "file %s, line %d: %s\n", script->filename, script->line, text); -#endif //BOTLIB -#ifdef MEQCC - printf("error: file %s, line %d: %s\n", script->filename, script->line, text); -#endif //MEQCC -#ifdef BSPC - Log_Print("error: file %s, line %d: %s\n", script->filename, script->line, text); -#endif //BSPC -} //end of the function ScriptError -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void QDECL ScriptWarning(script_t *script, char *str, ...) -{ - char text[1024]; - va_list ap; - - if (script->flags & SCFL_NOWARNINGS) return; - - va_start(ap, str); - vsprintf(text, str, ap); - va_end(ap); -#ifdef BOTLIB - botimport.Print(PRT_WARNING, "file %s, line %d: %s\n", script->filename, script->line, text); -#endif //BOTLIB -#ifdef MEQCC - printf("warning: file %s, line %d: %s\n", script->filename, script->line, text); -#endif //MEQCC -#ifdef BSPC - Log_Print("warning: file %s, line %d: %s\n", script->filename, script->line, text); -#endif //BSPC -} //end of the function ScriptWarning -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void SetScriptPunctuations(script_t *script, punctuation_t *p) -{ -#ifdef PUNCTABLE - if (p) PS_CreatePunctuationTable(script, p); - else PS_CreatePunctuationTable(script, default_punctuations); -#endif //PUNCTABLE - if (p) script->punctuations = p; - else script->punctuations = default_punctuations; -} //end of the function SetScriptPunctuations -//============================================================================ -// Reads spaces, tabs, C-like comments etc. -// When a newline character is found the scripts line counter is increased. -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PS_ReadWhiteSpace(script_t *script) -{ - while(1) - { - //skip white space - while(*script->script_p <= ' ') - { - if (!*script->script_p) return 0; - if (*script->script_p == '\n') script->line++; - script->script_p++; - } //end while - //skip comments - if (*script->script_p == '/') - { - //comments // - if (*(script->script_p+1) == '/') - { - script->script_p++; - do - { - script->script_p++; - if (!*script->script_p) return 0; - } //end do - while(*script->script_p != '\n'); - script->line++; - script->script_p++; - if (!*script->script_p) return 0; - continue; - } //end if - //comments /* */ - else if (*(script->script_p+1) == '*') - { - script->script_p++; - do - { - script->script_p++; - if (!*script->script_p) return 0; - if (*script->script_p == '\n') script->line++; - } //end do - while(!(*script->script_p == '*' && *(script->script_p+1) == '/')); - script->script_p++; - if (!*script->script_p) return 0; - script->script_p++; - if (!*script->script_p) return 0; - continue; - } //end if - } //end if - break; - } //end while - return 1; -} //end of the function PS_ReadWhiteSpace -//============================================================================ -// Reads an escape character. -// -// Parameter: script : script to read from -// ch : place to store the read escape character -// Returns: - -// Changes Globals: - -//============================================================================ -int PS_ReadEscapeCharacter(script_t *script, char *ch) -{ - int c, val, i; - - //step over the leading '\\' - script->script_p++; - //determine the escape character - switch(*script->script_p) - { - case '\\': c = '\\'; break; - case 'n': c = '\n'; break; - case 'r': c = '\r'; break; - case 't': c = '\t'; break; - case 'v': c = '\v'; break; - case 'b': c = '\b'; break; - case 'f': c = '\f'; break; - case 'a': c = '\a'; break; - case '\'': c = '\''; break; - case '\"': c = '\"'; break; - case '\?': c = '\?'; break; - case 'x': - { - script->script_p++; - for (i = 0, val = 0; ; i++, script->script_p++) - { - c = *script->script_p; - if (c >= '0' && c <= '9') c = c - '0'; - else if (c >= 'A' && c <= 'Z') c = c - 'A' + 10; - else if (c >= 'a' && c <= 'z') c = c - 'a' + 10; - else break; - val = (val << 4) + c; - } //end for - script->script_p--; - if (val > 0xFF) - { - ScriptWarning(script, "too large value in escape character"); - val = 0xFF; - } //end if - c = val; - break; - } //end case - default: //NOTE: decimal ASCII code, NOT octal - { - if (*script->script_p < '0' || *script->script_p > '9') ScriptError(script, "unknown escape char"); - for (i = 0, val = 0; ; i++, script->script_p++) - { - c = *script->script_p; - if (c >= '0' && c <= '9') c = c - '0'; - else break; - val = val * 10 + c; - } //end for - script->script_p--; - if (val > 0xFF) - { - ScriptWarning(script, "too large value in escape character"); - val = 0xFF; - } //end if - c = val; - break; - } //end default - } //end switch - //step over the escape character or the last digit of the number - script->script_p++; - //store the escape character - *ch = c; - //succesfully read escape character - return 1; -} //end of the function PS_ReadEscapeCharacter -//============================================================================ -// Reads C-like string. Escape characters are interpretted. -// Quotes are included with the string. -// Reads two strings with a white space between them as one string. -// -// Parameter: script : script to read from -// token : buffer to store the string -// Returns: qtrue when a string was read succesfully -// Changes Globals: - -//============================================================================ -int PS_ReadString(script_t *script, token_t *token, int quote) -{ - int len, tmpline; - char *tmpscript_p; - - if (quote == '\"') token->type = TT_STRING; - else token->type = TT_LITERAL; - - len = 0; - //leading quote - token->string[len++] = *script->script_p++; - // - while(1) - { - //minus 2 because trailing double quote and zero have to be appended - if (len >= MAX_TOKEN - 2) - { - ScriptError(script, "string longer than MAX_TOKEN = %d", MAX_TOKEN); - return 0; - } //end if - //if there is an escape character and - //if escape characters inside a string are allowed - if (*script->script_p == '\\' && !(script->flags & SCFL_NOSTRINGESCAPECHARS)) - { - if (!PS_ReadEscapeCharacter(script, &token->string[len])) - { - token->string[len] = 0; - return 0; - } //end if - len++; - } //end if - //if a trailing quote - else if (*script->script_p == quote) - { - //step over the double quote - script->script_p++; - //if white spaces in a string are not allowed - if (script->flags & SCFL_NOSTRINGWHITESPACES) break; - // - tmpscript_p = script->script_p; - tmpline = script->line; - //read unusefull stuff between possible two following strings - if (!PS_ReadWhiteSpace(script)) - { - script->script_p = tmpscript_p; - script->line = tmpline; - break; - } //end if - //if there's no leading double qoute - if (*script->script_p != quote) - { - script->script_p = tmpscript_p; - script->line = tmpline; - break; - } //end if - //step over the new leading double quote - script->script_p++; - } //end if - else - { - if (*script->script_p == '\0') - { - token->string[len] = 0; - ScriptError(script, "missing trailing quote"); - return 0; - } //end if - if (*script->script_p == '\n') - { - token->string[len] = 0; - ScriptError(script, "newline inside string %s", token->string); - return 0; - } //end if - token->string[len++] = *script->script_p++; - } //end else - } //end while - //trailing quote - token->string[len++] = quote; - //end string with a zero - token->string[len] = '\0'; - //the sub type is the length of the string - token->subtype = len; - return 1; -} //end of the function PS_ReadString -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PS_ReadName(script_t *script, token_t *token) -{ - int len = 0; - char c; - - token->type = TT_NAME; - do - { - token->string[len++] = *script->script_p++; - if (len >= MAX_TOKEN) - { - ScriptError(script, "name longer than MAX_TOKEN = %d", MAX_TOKEN); - return 0; - } //end if - c = *script->script_p; - } while ((c >= 'a' && c <= 'z') || - (c >= 'A' && c <= 'Z') || - (c >= '0' && c <= '9') || - c == '_'); - token->string[len] = '\0'; - //the sub type is the length of the name - token->subtype = len; - return 1; -} //end of the function PS_ReadName -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void NumberValue(char *string, int subtype, unsigned long int *intvalue, - double *floatvalue) -{ - unsigned long int dotfound = 0; - - *intvalue = 0; - *floatvalue = 0; - //floating point number - if (subtype & TT_FLOAT) - { - while(*string) - { - if (*string == '.') - { - if (dotfound) return; - dotfound = 10; - string++; - } //end if - if (dotfound) - { - *floatvalue = *floatvalue + (double) (*string - '0') / - (double) dotfound; - dotfound *= 10; - } //end if - else - { - *floatvalue = *floatvalue * 10.0 + (double) (*string - '0'); - } //end else - string++; - } //end while - *intvalue = (unsigned long) *floatvalue; - } //end if - else if (subtype & TT_DECIMAL) - { - while(*string) *intvalue = *intvalue * 10 + (*string++ - '0'); - *floatvalue = *intvalue; - } //end else if - else if (subtype & TT_HEX) - { - //step over the leading 0x or 0X - string += 2; - while(*string) - { - *intvalue <<= 4; - if (*string >= 'a' && *string <= 'f') *intvalue += *string - 'a' + 10; - else if (*string >= 'A' && *string <= 'F') *intvalue += *string - 'A' + 10; - else *intvalue += *string - '0'; - string++; - } //end while - *floatvalue = *intvalue; - } //end else if - else if (subtype & TT_OCTAL) - { - //step over the first zero - string += 1; - while(*string) *intvalue = (*intvalue << 3) + (*string++ - '0'); - *floatvalue = *intvalue; - } //end else if - else if (subtype & TT_BINARY) - { - //step over the leading 0b or 0B - string += 2; - while(*string) *intvalue = (*intvalue << 1) + (*string++ - '0'); - *floatvalue = *intvalue; - } //end else if -} //end of the function NumberValue -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PS_ReadNumber(script_t *script, token_t *token) -{ - int len = 0, i; - int octal, dot; - char c; -// unsigned long int intvalue = 0; -// double floatvalue = 0; - - token->type = TT_NUMBER; - //check for a hexadecimal number - if (*script->script_p == '0' && - (*(script->script_p + 1) == 'x' || - *(script->script_p + 1) == 'X')) - { - token->string[len++] = *script->script_p++; - token->string[len++] = *script->script_p++; - c = *script->script_p; - //hexadecimal - while((c >= '0' && c <= '9') || - (c >= 'a' && c <= 'f') || - (c >= 'A' && c <= 'A')) - { - token->string[len++] = *script->script_p++; - if (len >= MAX_TOKEN) - { - ScriptError(script, "hexadecimal number longer than MAX_TOKEN = %d", MAX_TOKEN); - return 0; - } //end if - c = *script->script_p; - } //end while - token->subtype |= TT_HEX; - } //end if -#ifdef BINARYNUMBERS - //check for a binary number - else if (*script->script_p == '0' && - (*(script->script_p + 1) == 'b' || - *(script->script_p + 1) == 'B')) - { - token->string[len++] = *script->script_p++; - token->string[len++] = *script->script_p++; - c = *script->script_p; - //binary - while(c == '0' || c == '1') - { - token->string[len++] = *script->script_p++; - if (len >= MAX_TOKEN) - { - ScriptError(script, "binary number longer than MAX_TOKEN = %d", MAX_TOKEN); - return 0; - } //end if - c = *script->script_p; - } //end while - token->subtype |= TT_BINARY; - } //end if -#endif //BINARYNUMBERS - else //decimal or octal integer or floating point number - { - octal = qfalse; - dot = qfalse; - if (*script->script_p == '0') octal = qtrue; - while(1) - { - c = *script->script_p; - if (c == '.') dot = qtrue; - else if (c == '8' || c == '9') octal = qfalse; - else if (c < '0' || c > '9') break; - token->string[len++] = *script->script_p++; - if (len >= MAX_TOKEN - 1) - { - ScriptError(script, "number longer than MAX_TOKEN = %d", MAX_TOKEN); - return 0; - } //end if - } //end while - if (octal) token->subtype |= TT_OCTAL; - else token->subtype |= TT_DECIMAL; - if (dot) token->subtype |= TT_FLOAT; - } //end else - for (i = 0; i < 2; i++) - { - c = *script->script_p; - //check for a LONG number - if ( (c == 'l' || c == 'L') // bk001204 - brackets - && !(token->subtype & TT_LONG)) - { - script->script_p++; - token->subtype |= TT_LONG; - } //end if - //check for an UNSIGNED number - else if ( (c == 'u' || c == 'U') // bk001204 - brackets - && !(token->subtype & (TT_UNSIGNED | TT_FLOAT))) - { - script->script_p++; - token->subtype |= TT_UNSIGNED; - } //end if - } //end for - token->string[len] = '\0'; -#ifdef NUMBERVALUE - NumberValue(token->string, token->subtype, &token->intvalue, &token->floatvalue); -#endif //NUMBERVALUE - if (!(token->subtype & TT_FLOAT)) token->subtype |= TT_INTEGER; - return 1; -} //end of the function PS_ReadNumber -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PS_ReadLiteral(script_t *script, token_t *token) -{ - token->type = TT_LITERAL; - //first quote - token->string[0] = *script->script_p++; - //check for end of file - if (!*script->script_p) - { - ScriptError(script, "end of file before trailing \'"); - return 0; - } //end if - //if it is an escape character - if (*script->script_p == '\\') - { - if (!PS_ReadEscapeCharacter(script, &token->string[1])) return 0; - } //end if - else - { - token->string[1] = *script->script_p++; - } //end else - //check for trailing quote - if (*script->script_p != '\'') - { - ScriptWarning(script, "too many characters in literal, ignored"); - while(*script->script_p && - *script->script_p != '\'' && - *script->script_p != '\n') - { - script->script_p++; - } //end while - if (*script->script_p == '\'') script->script_p++; - } //end if - //store the trailing quote - token->string[2] = *script->script_p++; - //store trailing zero to end the string - token->string[3] = '\0'; - //the sub type is the integer literal value - token->subtype = token->string[1]; - // - return 1; -} //end of the function PS_ReadLiteral -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PS_ReadPunctuation(script_t *script, token_t *token) -{ - int len; - char *p; - punctuation_t *punc; - -#ifdef PUNCTABLE - for (punc = script->punctuationtable[(unsigned int)*script->script_p]; punc; punc = punc->next) - { -#else - int i; - - for (i = 0; script->punctuations[i].p; i++) - { - punc = &script->punctuations[i]; -#endif //PUNCTABLE - p = punc->p; - len = strlen(p); - //if the script contains at least as much characters as the punctuation - if (script->script_p + len <= script->end_p) - { - //if the script contains the punctuation - if (!strncmp(script->script_p, p, len)) - { - strncpy(token->string, p, MAX_TOKEN); - script->script_p += len; - token->type = TT_PUNCTUATION; - //sub type is the number of the punctuation - token->subtype = punc->n; - return 1; - } //end if - } //end if - } //end for - return 0; -} //end of the function PS_ReadPunctuation -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PS_ReadPrimitive(script_t *script, token_t *token) -{ - int len; - - len = 0; - while(*script->script_p > ' ' && *script->script_p != ';') - { - if (len >= MAX_TOKEN) - { - ScriptError(script, "primitive token longer than MAX_TOKEN = %d", MAX_TOKEN); - return 0; - } //end if - token->string[len++] = *script->script_p++; - } //end while - token->string[len] = 0; - //copy the token into the script structure - Com_Memcpy(&script->token, token, sizeof(token_t)); - //primitive reading successfull - return 1; -} //end of the function PS_ReadPrimitive -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PS_ReadToken(script_t *script, token_t *token) -{ - //if there is a token available (from UnreadToken) - if (script->tokenavailable) - { - script->tokenavailable = 0; - Com_Memcpy(token, &script->token, sizeof(token_t)); - return 1; - } //end if - //save script pointer - script->lastscript_p = script->script_p; - //save line counter - script->lastline = script->line; - //clear the token stuff - Com_Memset(token, 0, sizeof(token_t)); - //start of the white space - script->whitespace_p = script->script_p; - token->whitespace_p = script->script_p; - //read unusefull stuff - if (!PS_ReadWhiteSpace(script)) return 0; - //end of the white space - script->endwhitespace_p = script->script_p; - token->endwhitespace_p = script->script_p; - //line the token is on - token->line = script->line; - //number of lines crossed before token - token->linescrossed = script->line - script->lastline; - //if there is a leading double quote - if (*script->script_p == '\"') - { - if (!PS_ReadString(script, token, '\"')) return 0; - } //end if - //if an literal - else if (*script->script_p == '\'') - { - //if (!PS_ReadLiteral(script, token)) return 0; - if (!PS_ReadString(script, token, '\'')) return 0; - } //end if - //if there is a number - else if ((*script->script_p >= '0' && *script->script_p <= '9') || - (*script->script_p == '.' && - (*(script->script_p + 1) >= '0' && *(script->script_p + 1) <= '9'))) - { - if (!PS_ReadNumber(script, token)) return 0; - } //end if - //if this is a primitive script - else if (script->flags & SCFL_PRIMITIVE) - { - return PS_ReadPrimitive(script, token); - } //end else if - //if there is a name - else if ((*script->script_p >= 'a' && *script->script_p <= 'z') || - (*script->script_p >= 'A' && *script->script_p <= 'Z') || - *script->script_p == '_') - { - if (!PS_ReadName(script, token)) return 0; - } //end if - //check for punctuations - else if (!PS_ReadPunctuation(script, token)) - { - ScriptError(script, "can't read token"); - return 0; - } //end if - //copy the token into the script structure - Com_Memcpy(&script->token, token, sizeof(token_t)); - //succesfully read a token - return 1; -} //end of the function PS_ReadToken -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PS_ExpectTokenString(script_t *script, char *string) -{ - token_t token; - - if (!PS_ReadToken(script, &token)) - { - ScriptError(script, "couldn't find expected %s", string); - return 0; - } //end if - - if (strcmp(token.string, string)) - { - ScriptError(script, "expected %s, found %s", string, token.string); - return 0; - } //end if - return 1; -} //end of the function PS_ExpectToken -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PS_ExpectTokenType(script_t *script, int type, int subtype, token_t *token) -{ - char str[MAX_TOKEN]; - - if (!PS_ReadToken(script, token)) - { - ScriptError(script, "couldn't read expected token"); - return 0; - } //end if - - if (token->type != type) - { - if (type == TT_STRING) strcpy(str, "string"); - if (type == TT_LITERAL) strcpy(str, "literal"); - if (type == TT_NUMBER) strcpy(str, "number"); - if (type == TT_NAME) strcpy(str, "name"); - if (type == TT_PUNCTUATION) strcpy(str, "punctuation"); - ScriptError(script, "expected a %s, found %s", str, token->string); - return 0; - } //end if - if (token->type == TT_NUMBER) - { - if ((token->subtype & subtype) != subtype) - { - if (subtype & TT_DECIMAL) strcpy(str, "decimal"); - if (subtype & TT_HEX) strcpy(str, "hex"); - if (subtype & TT_OCTAL) strcpy(str, "octal"); - if (subtype & TT_BINARY) strcpy(str, "binary"); - if (subtype & TT_LONG) strcat(str, " long"); - if (subtype & TT_UNSIGNED) strcat(str, " unsigned"); - if (subtype & TT_FLOAT) strcat(str, " float"); - if (subtype & TT_INTEGER) strcat(str, " integer"); - ScriptError(script, "expected %s, found %s", str, token->string); - return 0; - } //end if - } //end if - else if (token->type == TT_PUNCTUATION) - { - if (subtype < 0) - { - ScriptError(script, "BUG: wrong punctuation subtype"); - return 0; - } //end if - if (token->subtype != subtype) - { - ScriptError(script, "expected %s, found %s", - script->punctuations[subtype], token->string); - return 0; - } //end if - } //end else if - return 1; -} //end of the function PS_ExpectTokenType -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PS_ExpectAnyToken(script_t *script, token_t *token) -{ - if (!PS_ReadToken(script, token)) - { - ScriptError(script, "couldn't read expected token"); - return 0; - } //end if - else - { - return 1; - } //end else -} //end of the function PS_ExpectAnyToken -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PS_CheckTokenString(script_t *script, char *string) -{ - token_t tok; - - if (!PS_ReadToken(script, &tok)) return 0; - //if the token is available - if (!strcmp(tok.string, string)) return 1; - //token not available - script->script_p = script->lastscript_p; - return 0; -} //end of the function PS_CheckTokenString -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PS_CheckTokenType(script_t *script, int type, int subtype, token_t *token) -{ - token_t tok; - - if (!PS_ReadToken(script, &tok)) return 0; - //if the type matches - if (tok.type == type && - (tok.subtype & subtype) == subtype) - { - Com_Memcpy(token, &tok, sizeof(token_t)); - return 1; - } //end if - //token is not available - script->script_p = script->lastscript_p; - return 0; -} //end of the function PS_CheckTokenType -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int PS_SkipUntilString(script_t *script, char *string) -{ - token_t token; - - while(PS_ReadToken(script, &token)) - { - if (!strcmp(token.string, string)) return 1; - } //end while - return 0; -} //end of the function PS_SkipUntilString -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PS_UnreadLastToken(script_t *script) -{ - script->tokenavailable = 1; -} //end of the function UnreadLastToken -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PS_UnreadToken(script_t *script, token_t *token) -{ - Com_Memcpy(&script->token, token, sizeof(token_t)); - script->tokenavailable = 1; -} //end of the function UnreadToken -//============================================================================ -// returns the next character of the read white space, returns NULL if none -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -char PS_NextWhiteSpaceChar(script_t *script) -{ - if (script->whitespace_p != script->endwhitespace_p) - { - return *script->whitespace_p++; - } //end if - else - { - return 0; - } //end else -} //end of the function PS_NextWhiteSpaceChar -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void StripDoubleQuotes(char *string) -{ - if (*string == '\"') - { - strcpy(string, string+1); - } //end if - if (string[strlen(string)-1] == '\"') - { - string[strlen(string)-1] = '\0'; - } //end if -} //end of the function StripDoubleQuotes -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void StripSingleQuotes(char *string) -{ - if (*string == '\'') - { - strcpy(string, string+1); - } //end if - if (string[strlen(string)-1] == '\'') - { - string[strlen(string)-1] = '\0'; - } //end if -} //end of the function StripSingleQuotes -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -double ReadSignedFloat(script_t *script) -{ - token_t token; - double sign = 1.0; - - PS_ExpectAnyToken(script, &token); - if (!strcmp(token.string, "-")) - { - sign = -1.0; - PS_ExpectTokenType(script, TT_NUMBER, 0, &token); - } //end if - else if (token.type != TT_NUMBER) - { - ScriptError(script, "expected float value, found %s\n", token.string); - } //end else if - return sign * token.floatvalue; -} //end of the function ReadSignedFloat -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -signed long int ReadSignedInt(script_t *script) -{ - token_t token; - signed long int sign = 1; - - PS_ExpectAnyToken(script, &token); - if (!strcmp(token.string, "-")) - { - sign = -1; - PS_ExpectTokenType(script, TT_NUMBER, TT_INTEGER, &token); - } //end if - else if (token.type != TT_NUMBER || token.subtype == TT_FLOAT) - { - ScriptError(script, "expected integer value, found %s\n", token.string); - } //end else if - return sign * token.intvalue; -} //end of the function ReadSignedInt -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void SetScriptFlags(script_t *script, int flags) -{ - script->flags = flags; -} //end of the function SetScriptFlags -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int GetScriptFlags(script_t *script) -{ - return script->flags; -} //end of the function GetScriptFlags -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void ResetScript(script_t *script) -{ - //pointer in script buffer - script->script_p = script->buffer; - //pointer in script buffer before reading token - script->lastscript_p = script->buffer; - //begin of white space - script->whitespace_p = NULL; - //end of white space - script->endwhitespace_p = NULL; - //set if there's a token available in script->token - script->tokenavailable = 0; - // - script->line = 1; - script->lastline = 1; - //clear the saved token - Com_Memset(&script->token, 0, sizeof(token_t)); -} //end of the function ResetScript -//============================================================================ -// returns true if at the end of the script -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int EndOfScript(script_t *script) -{ - return script->script_p >= script->end_p; -} //end of the function EndOfScript -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int NumLinesCrossed(script_t *script) -{ - return script->line - script->lastline; -} //end of the function NumLinesCrossed -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int ScriptSkipTo(script_t *script, char *value) -{ - int len; - char firstchar; - - firstchar = *value; - len = strlen(value); - do - { - if (!PS_ReadWhiteSpace(script)) return 0; - if (*script->script_p == firstchar) - { - if (!strncmp(script->script_p, value, len)) - { - return 1; - } //end if - } //end if - script->script_p++; - } while(1); -} //end of the function ScriptSkipTo -#ifndef BOTLIB -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -int FileLength(FILE *fp) -{ - int pos; - int end; - - pos = ftell(fp); - fseek(fp, 0, SEEK_END); - end = ftell(fp); - fseek(fp, pos, SEEK_SET); - - return end; -} //end of the function FileLength -#endif -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -script_t *LoadScriptFile(const char *filename) -{ -#ifdef BOTLIB - fileHandle_t fp; - char pathname[MAX_QPATH]; -#else - FILE *fp; -#endif - int length; - void *buffer; - script_t *script; - -#ifdef BOTLIB - if (strlen(basefolder)) - Com_sprintf(pathname, sizeof(pathname), "%s/%s", basefolder, filename); - else - Com_sprintf(pathname, sizeof(pathname), "%s", filename); - length = botimport.FS_FOpenFile( pathname, &fp, FS_READ ); - if (!fp) return NULL; -#else - fp = fopen(filename, "rb"); - if (!fp) return NULL; - - length = FileLength(fp); -#endif - - buffer = GetClearedMemory(sizeof(script_t) + length + 1); - script = (script_t *) buffer; - Com_Memset(script, 0, sizeof(script_t)); - strcpy(script->filename, filename); - script->buffer = (char *) buffer + sizeof(script_t); - script->buffer[length] = 0; - script->length = length; - //pointer in script buffer - script->script_p = script->buffer; - //pointer in script buffer before reading token - script->lastscript_p = script->buffer; - //pointer to end of script buffer - script->end_p = &script->buffer[length]; - //set if there's a token available in script->token - script->tokenavailable = 0; - // - script->line = 1; - script->lastline = 1; - // - SetScriptPunctuations(script, NULL); - // -#ifdef BOTLIB - botimport.FS_Read(script->buffer, length, fp); - botimport.FS_FCloseFile(fp); -#else - if (fread(script->buffer, length, 1, fp) != 1) - { - FreeMemory(buffer); - script = NULL; - } //end if - fclose(fp); -#endif - // - script->length = COM_Compress(script->buffer); - - return script; -} //end of the function LoadScriptFile -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -script_t *LoadScriptMemory(char *ptr, int length, char *name) -{ - void *buffer; - script_t *script; - - buffer = GetClearedMemory(sizeof(script_t) + length + 1); - script = (script_t *) buffer; - Com_Memset(script, 0, sizeof(script_t)); - strcpy(script->filename, name); - script->buffer = (char *) buffer + sizeof(script_t); - script->buffer[length] = 0; - script->length = length; - //pointer in script buffer - script->script_p = script->buffer; - //pointer in script buffer before reading token - script->lastscript_p = script->buffer; - //pointer to end of script buffer - script->end_p = &script->buffer[length]; - //set if there's a token available in script->token - script->tokenavailable = 0; - // - script->line = 1; - script->lastline = 1; - // - SetScriptPunctuations(script, NULL); - // - Com_Memcpy(script->buffer, ptr, length); - // - return script; -} //end of the function LoadScriptMemory -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void FreeScript(script_t *script) -{ -#ifdef PUNCTABLE - if (script->punctuationtable) FreeMemory(script->punctuationtable); -#endif //PUNCTABLE - FreeMemory(script); -} //end of the function FreeScript -//============================================================================ -// -// Parameter: - -// Returns: - -// Changes Globals: - -//============================================================================ -void PS_SetBaseFolder(char *path) -{ -#ifdef BSPC - sprintf(basefolder, path); -#else - Com_sprintf(basefolder, sizeof(basefolder), path); -#endif -} //end of the function PS_SetBaseFolder diff --git a/src/botlib/l_script.h b/src/botlib/l_script.h deleted file mode 100644 index a779e623..00000000 --- a/src/botlib/l_script.h +++ /dev/null @@ -1,248 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: l_script.h - * - * desc: lexicographical parser - * - * $Archive: /source/code/botlib/l_script.h $ - * - *****************************************************************************/ - -//undef if binary numbers of the form 0b... or 0B... are not allowed -#define BINARYNUMBERS -//undef if not using the token.intvalue and token.floatvalue -#define NUMBERVALUE -//use dollar sign also as punctuation -#define DOLLAR - -//maximum token length -#define MAX_TOKEN 1024 - -#if defined(BSPC) && !defined(QDECL) -#define QDECL -#endif - - -//script flags -#define SCFL_NOERRORS 0x0001 -#define SCFL_NOWARNINGS 0x0002 -#define SCFL_NOSTRINGWHITESPACES 0x0004 -#define SCFL_NOSTRINGESCAPECHARS 0x0008 -#define SCFL_PRIMITIVE 0x0010 -#define SCFL_NOBINARYNUMBERS 0x0020 -#define SCFL_NONUMBERVALUES 0x0040 - -//token types -#define TT_STRING 1 // string -#define TT_LITERAL 2 // literal -#define TT_NUMBER 3 // number -#define TT_NAME 4 // name -#define TT_PUNCTUATION 5 // punctuation - -//string sub type -//--------------- -// the length of the string -//literal sub type -//---------------- -// the ASCII code of the literal -//number sub type -//--------------- -#define TT_DECIMAL 0x0008 // decimal number -#define TT_HEX 0x0100 // hexadecimal number -#define TT_OCTAL 0x0200 // octal number -#ifdef BINARYNUMBERS -#define TT_BINARY 0x0400 // binary number -#endif //BINARYNUMBERS -#define TT_FLOAT 0x0800 // floating point number -#define TT_INTEGER 0x1000 // integer number -#define TT_LONG 0x2000 // long number -#define TT_UNSIGNED 0x4000 // unsigned number -//punctuation sub type -//-------------------- -#define P_RSHIFT_ASSIGN 1 -#define P_LSHIFT_ASSIGN 2 -#define P_PARMS 3 -#define P_PRECOMPMERGE 4 - -#define P_LOGIC_AND 5 -#define P_LOGIC_OR 6 -#define P_LOGIC_GEQ 7 -#define P_LOGIC_LEQ 8 -#define P_LOGIC_EQ 9 -#define P_LOGIC_UNEQ 10 - -#define P_MUL_ASSIGN 11 -#define P_DIV_ASSIGN 12 -#define P_MOD_ASSIGN 13 -#define P_ADD_ASSIGN 14 -#define P_SUB_ASSIGN 15 -#define P_INC 16 -#define P_DEC 17 - -#define P_BIN_AND_ASSIGN 18 -#define P_BIN_OR_ASSIGN 19 -#define P_BIN_XOR_ASSIGN 20 -#define P_RSHIFT 21 -#define P_LSHIFT 22 - -#define P_POINTERREF 23 -#define P_CPP1 24 -#define P_CPP2 25 -#define P_MUL 26 -#define P_DIV 27 -#define P_MOD 28 -#define P_ADD 29 -#define P_SUB 30 -#define P_ASSIGN 31 - -#define P_BIN_AND 32 -#define P_BIN_OR 33 -#define P_BIN_XOR 34 -#define P_BIN_NOT 35 - -#define P_LOGIC_NOT 36 -#define P_LOGIC_GREATER 37 -#define P_LOGIC_LESS 38 - -#define P_REF 39 -#define P_COMMA 40 -#define P_SEMICOLON 41 -#define P_COLON 42 -#define P_QUESTIONMARK 43 - -#define P_PARENTHESESOPEN 44 -#define P_PARENTHESESCLOSE 45 -#define P_BRACEOPEN 46 -#define P_BRACECLOSE 47 -#define P_SQBRACKETOPEN 48 -#define P_SQBRACKETCLOSE 49 -#define P_BACKSLASH 50 - -#define P_PRECOMP 51 -#define P_DOLLAR 52 -//name sub type -//------------- -// the length of the name - -//punctuation -typedef struct punctuation_s -{ - char *p; //punctuation character(s) - int n; //punctuation indication - struct punctuation_s *next; //next punctuation -} punctuation_t; - -//token -typedef struct token_s -{ - char string[MAX_TOKEN]; //available token - int type; //last read token type - int subtype; //last read token sub type -#ifdef NUMBERVALUE - unsigned long int intvalue; //integer value - double floatvalue; //floating point value -#endif //NUMBERVALUE - char *whitespace_p; //start of white space before token - char *endwhitespace_p; //start of white space before token - int line; //line the token was on - int linescrossed; //lines crossed in white space - struct token_s *next; //next token in chain -} token_t; - -//script file -typedef struct script_s -{ - char filename[1024]; //file name of the script - char *buffer; //buffer containing the script - char *script_p; //current pointer in the script - char *end_p; //pointer to the end of the script - char *lastscript_p; //script pointer before reading token - char *whitespace_p; //begin of the white space - char *endwhitespace_p; //end of the white space - int length; //length of the script in bytes - int line; //current line in script - int lastline; //line before reading token - int tokenavailable; //set by UnreadLastToken - int flags; //several script flags - punctuation_t *punctuations; //the punctuations used in the script - punctuation_t **punctuationtable; - token_t token; //available token - struct script_s *next; //next script in a chain -} script_t; - -//read a token from the script -int PS_ReadToken(script_t *script, token_t *token); -//expect a certain token -int PS_ExpectTokenString(script_t *script, char *string); -//expect a certain token type -int PS_ExpectTokenType(script_t *script, int type, int subtype, token_t *token); -//expect a token -int PS_ExpectAnyToken(script_t *script, token_t *token); -//returns true when the token is available -int PS_CheckTokenString(script_t *script, char *string); -//returns true an reads the token when a token with the given type is available -int PS_CheckTokenType(script_t *script, int type, int subtype, token_t *token); -//skip tokens until the given token string is read -int PS_SkipUntilString(script_t *script, char *string); -//unread the last token read from the script -void PS_UnreadLastToken(script_t *script); -//unread the given token -void PS_UnreadToken(script_t *script, token_t *token); -//returns the next character of the read white space, returns NULL if none -char PS_NextWhiteSpaceChar(script_t *script); -//remove any leading and trailing double quotes from the token -void StripDoubleQuotes(char *string); -//remove any leading and trailing single quotes from the token -void StripSingleQuotes(char *string); -//read a possible signed integer -signed long int ReadSignedInt(script_t *script); -//read a possible signed floating point number -double ReadSignedFloat(script_t *script); -//set an array with punctuations, NULL restores default C/C++ set -void SetScriptPunctuations(script_t *script, punctuation_t *p); -//set script flags -void SetScriptFlags(script_t *script, int flags); -//get script flags -int GetScriptFlags(script_t *script); -//reset a script -void ResetScript(script_t *script); -//returns true if at the end of the script -int EndOfScript(script_t *script); -//returns a pointer to the punctuation with the given number -char *PunctuationFromNum(script_t *script, int num); -//load a script from the given file at the given offset with the given length -script_t *LoadScriptFile(const char *filename); -//load a script from the given memory with the given length -script_t *LoadScriptMemory(char *ptr, int length, char *name); -//free a script -void FreeScript(script_t *script); -//set the base folder to load files from -void PS_SetBaseFolder(char *path); -//print a script error with filename and line number -void QDECL ScriptError(script_t *script, char *str, ...); -//print a script warning with filename and line number -void QDECL ScriptWarning(script_t *script, char *str, ...); - - diff --git a/src/botlib/l_struct.c b/src/botlib/l_struct.c deleted file mode 100644 index 0dd38f58..00000000 --- a/src/botlib/l_struct.c +++ /dev/null @@ -1,463 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: l_struct.c - * - * desc: structure reading / writing - * - * $Archive: /MissionPack/CODE/botlib/l_struct.c $ - * - *****************************************************************************/ - -#ifdef BOTLIB -#include "../qcommon/q_shared.h" -#include "botlib.h" //for the include of be_interface.h -#include "l_script.h" -#include "l_precomp.h" -#include "l_struct.h" -#include "l_utils.h" -#include "be_interface.h" -#endif //BOTLIB - -#ifdef BSPC -//include files for usage in the BSP Converter -#include "../bspc/qbsp.h" -#include "../bspc/l_log.h" -#include "../bspc/l_mem.h" -#include "l_precomp.h" -#include "l_struct.h" - -#define qtrue true -#define qfalse false -#endif //BSPC - -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -fielddef_t *FindField(fielddef_t *defs, char *name) -{ - int i; - - for (i = 0; defs[i].name; i++) - { - if (!strcmp(defs[i].name, name)) return &defs[i]; - } //end for - return NULL; -} //end of the function FindField -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -qboolean ReadNumber(source_t *source, fielddef_t *fd, void *p) -{ - token_t token; - int negative = qfalse; - long int intval, intmin = 0, intmax = 0; - double floatval; - - if (!PC_ExpectAnyToken(source, &token)) return 0; - - //check for minus sign - if (token.type == TT_PUNCTUATION) - { - if (fd->type & FT_UNSIGNED) - { - SourceError(source, "expected unsigned value, found %s", token.string); - return 0; - } //end if - //if not a minus sign - if (strcmp(token.string, "-")) - { - SourceError(source, "unexpected punctuation %s", token.string); - return 0; - } //end if - negative = qtrue; - //read the number - if (!PC_ExpectAnyToken(source, &token)) return 0; - } //end if - //check if it is a number - if (token.type != TT_NUMBER) - { - SourceError(source, "expected number, found %s", token.string); - return 0; - } //end if - //check for a float value - if (token.subtype & TT_FLOAT) - { - if ((fd->type & FT_TYPE) != FT_FLOAT) - { - SourceError(source, "unexpected float"); - return 0; - } //end if - floatval = token.floatvalue; - if (negative) floatval = -floatval; - if (fd->type & FT_BOUNDED) - { - if (floatval < fd->floatmin || floatval > fd->floatmax) - { - SourceError(source, "float out of range [%f, %f]", fd->floatmin, fd->floatmax); - return 0; - } //end if - } //end if - *(float *) p = (float) floatval; - return 1; - } //end if - // - intval = token.intvalue; - if (negative) intval = -intval; - //check bounds - if ((fd->type & FT_TYPE) == FT_CHAR) - { - if (fd->type & FT_UNSIGNED) {intmin = 0; intmax = 255;} - else {intmin = -128; intmax = 127;} - } //end if - if ((fd->type & FT_TYPE) == FT_INT) - { - if (fd->type & FT_UNSIGNED) {intmin = 0; intmax = 65535;} - else {intmin = -32768; intmax = 32767;} - } //end else if - if ((fd->type & FT_TYPE) == FT_CHAR || (fd->type & FT_TYPE) == FT_INT) - { - if (fd->type & FT_BOUNDED) - { - intmin = Maximum(intmin, fd->floatmin); - intmax = Minimum(intmax, fd->floatmax); - } //end if - if (intval < intmin || intval > intmax) - { - SourceError(source, "value %d out of range [%d, %d]", intval, intmin, intmax); - return 0; - } //end if - } //end if - else if ((fd->type & FT_TYPE) == FT_FLOAT) - { - if (fd->type & FT_BOUNDED) - { - if (intval < fd->floatmin || intval > fd->floatmax) - { - SourceError(source, "value %d out of range [%f, %f]", intval, fd->floatmin, fd->floatmax); - return 0; - } //end if - } //end if - } //end else if - //store the value - if ((fd->type & FT_TYPE) == FT_CHAR) - { - if (fd->type & FT_UNSIGNED) *(unsigned char *) p = (unsigned char) intval; - else *(char *) p = (char) intval; - } //end if - else if ((fd->type & FT_TYPE) == FT_INT) - { - if (fd->type & FT_UNSIGNED) *(unsigned int *) p = (unsigned int) intval; - else *(int *) p = (int) intval; - } //end else - else if ((fd->type & FT_TYPE) == FT_FLOAT) - { - *(float *) p = (float) intval; - } //end else - return 1; -} //end of the function ReadNumber -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -qboolean ReadChar(source_t *source, fielddef_t *fd, void *p) -{ - token_t token; - - if (!PC_ExpectAnyToken(source, &token)) return 0; - - //take literals into account - if (token.type == TT_LITERAL) - { - StripSingleQuotes(token.string); - *(char *) p = token.string[0]; - } //end if - else - { - PC_UnreadLastToken(source); - if (!ReadNumber(source, fd, p)) return 0; - } //end if - return 1; -} //end of the function ReadChar -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int ReadString(source_t *source, fielddef_t *fd, void *p) -{ - token_t token; - - if (!PC_ExpectTokenType(source, TT_STRING, 0, &token)) return 0; - //remove the double quotes - StripDoubleQuotes(token.string); - //copy the string - strncpy((char *) p, token.string, MAX_STRINGFIELD); - //make sure the string is closed with a zero - ((char *)p)[MAX_STRINGFIELD-1] = '\0'; - // - return 1; -} //end of the function ReadString -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int ReadStructure(source_t *source, structdef_t *def, char *structure) -{ - token_t token; - fielddef_t *fd; - void *p; - int num; - - if (!PC_ExpectTokenString(source, "{")) return 0; - while(1) - { - if (!PC_ExpectAnyToken(source, &token)) return qfalse; - //if end of structure - if (!strcmp(token.string, "}")) break; - //find the field with the name - fd = FindField(def->fields, token.string); - if (!fd) - { - SourceError(source, "unknown structure field %s", token.string); - return qfalse; - } //end if - if (fd->type & FT_ARRAY) - { - num = fd->maxarray; - if (!PC_ExpectTokenString(source, "{")) return qfalse; - } //end if - else - { - num = 1; - } //end else - p = (void *)(structure + fd->offset); - while (num-- > 0) - { - if (fd->type & FT_ARRAY) - { - if (PC_CheckTokenString(source, "}")) break; - } //end if - switch(fd->type & FT_TYPE) - { - case FT_CHAR: - { - if (!ReadChar(source, fd, p)) return qfalse; - p = (char *) p + sizeof(char); - break; - } //end case - case FT_INT: - { - if (!ReadNumber(source, fd, p)) return qfalse; - p = (char *) p + sizeof(int); - break; - } //end case - case FT_FLOAT: - { - if (!ReadNumber(source, fd, p)) return qfalse; - p = (char *) p + sizeof(float); - break; - } //end case - case FT_STRING: - { - if (!ReadString(source, fd, p)) return qfalse; - p = (char *) p + MAX_STRINGFIELD; - break; - } //end case - case FT_STRUCT: - { - if (!fd->substruct) - { - SourceError(source, "BUG: no sub structure defined"); - return qfalse; - } //end if - ReadStructure(source, fd->substruct, (char *) p); - p = (char *) p + fd->substruct->size; - break; - } //end case - } //end switch - if (fd->type & FT_ARRAY) - { - if (!PC_ExpectAnyToken(source, &token)) return qfalse; - if (!strcmp(token.string, "}")) break; - if (strcmp(token.string, ",")) - { - SourceError(source, "expected a comma, found %s", token.string); - return qfalse; - } //end if - } //end if - } //end while - } //end while - return qtrue; -} //end of the function ReadStructure -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WriteIndent(FILE *fp, int indent) -{ - while(indent-- > 0) - { - if (fprintf(fp, "\t") < 0) return qfalse; - } //end while - return qtrue; -} //end of the function WriteIndent -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WriteFloat(FILE *fp, float value) -{ - char buf[128]; - int l; - - sprintf(buf, "%f", value); - l = strlen(buf); - //strip any trailing zeros - while(l-- > 1) - { - if (buf[l] != '0' && buf[l] != '.') break; - if (buf[l] == '.') - { - buf[l] = 0; - break; - } //end if - buf[l] = 0; - } //end while - //write the float to file - if (fprintf(fp, "%s", buf) < 0) return 0; - return 1; -} //end of the function WriteFloat -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WriteStructWithIndent(FILE *fp, structdef_t *def, char *structure, int indent) -{ - int i, num; - void *p; - fielddef_t *fd; - - if (!WriteIndent(fp, indent)) return qfalse; - if (fprintf(fp, "{\r\n") < 0) return qfalse; - - indent++; - for (i = 0; def->fields[i].name; i++) - { - fd = &def->fields[i]; - if (!WriteIndent(fp, indent)) return qfalse; - if (fprintf(fp, "%s\t", fd->name) < 0) return qfalse; - p = (void *)(structure + fd->offset); - if (fd->type & FT_ARRAY) - { - num = fd->maxarray; - if (fprintf(fp, "{") < 0) return qfalse; - } //end if - else - { - num = 1; - } //end else - while(num-- > 0) - { - switch(fd->type & FT_TYPE) - { - case FT_CHAR: - { - if (fprintf(fp, "%d", *(char *) p) < 0) return qfalse; - p = (char *) p + sizeof(char); - break; - } //end case - case FT_INT: - { - if (fprintf(fp, "%d", *(int *) p) < 0) return qfalse; - p = (char *) p + sizeof(int); - break; - } //end case - case FT_FLOAT: - { - if (!WriteFloat(fp, *(float *)p)) return qfalse; - p = (char *) p + sizeof(float); - break; - } //end case - case FT_STRING: - { - if (fprintf(fp, "\"%s\"", (char *) p) < 0) return qfalse; - p = (char *) p + MAX_STRINGFIELD; - break; - } //end case - case FT_STRUCT: - { - if (!WriteStructWithIndent(fp, fd->substruct, structure, indent)) return qfalse; - p = (char *) p + fd->substruct->size; - break; - } //end case - } //end switch - if (fd->type & FT_ARRAY) - { - if (num > 0) - { - if (fprintf(fp, ",") < 0) return qfalse; - } //end if - else - { - if (fprintf(fp, "}") < 0) return qfalse; - } //end else - } //end if - } //end while - if (fprintf(fp, "\r\n") < 0) return qfalse; - } //end for - indent--; - - if (!WriteIndent(fp, indent)) return qfalse; - if (fprintf(fp, "}\r\n") < 0) return qfalse; - return qtrue; -} //end of the function WriteStructWithIndent -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WriteStructure(FILE *fp, structdef_t *def, char *structure) -{ - return WriteStructWithIndent(fp, def, structure, 0); -} //end of the function WriteStructure - diff --git a/src/botlib/l_struct.h b/src/botlib/l_struct.h deleted file mode 100644 index a9f23c8f..00000000 --- a/src/botlib/l_struct.h +++ /dev/null @@ -1,76 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: l_struct.h - * - * desc: structure reading/writing - * - * $Archive: /source/code/botlib/l_struct.h $ - * - *****************************************************************************/ - - -#define MAX_STRINGFIELD 80 -//field types -#define FT_CHAR 1 // char -#define FT_INT 2 // int -#define FT_FLOAT 3 // float -#define FT_STRING 4 // char [MAX_STRINGFIELD] -#define FT_STRUCT 6 // struct (sub structure) -//type only mask -#define FT_TYPE 0x00FF // only type, clear subtype -//sub types -#define FT_ARRAY 0x0100 // array of type -#define FT_BOUNDED 0x0200 // bounded value -#define FT_UNSIGNED 0x0400 - -//structure field definition -typedef struct fielddef_s -{ - char *name; //name of the field - int offset; //offset in the structure - int type; //type of the field - //type specific fields - int maxarray; //maximum array size - float floatmin, floatmax; //float min and max - struct structdef_s *substruct; //sub structure -} fielddef_t; - -//structure definition -typedef struct structdef_s -{ - int size; - fielddef_t *fields; -} structdef_t; - -//read a structure from a script -int ReadStructure(source_t *source, structdef_t *def, char *structure); -//write a structure to a file -int WriteStructure(FILE *fp, structdef_t *def, char *structure); -//writes indents -int WriteIndent(FILE *fp, int indent); -//writes a float without traling zeros -int WriteFloat(FILE *fp, float value); - - diff --git a/src/botlib/l_utils.h b/src/botlib/l_utils.h deleted file mode 100644 index f6e54890..00000000 --- a/src/botlib/l_utils.h +++ /dev/null @@ -1,38 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: l_util.h - * - * desc: utils - * - * $Archive: /source/code/botlib/l_util.h $ - * - *****************************************************************************/ - -#define Vector2Angles(v,a) vectoangles(v,a) -#ifndef MAX_PATH -#define MAX_PATH MAX_QPATH -#endif -#define Maximum(x,y) (x > y ? x : y) -#define Minimum(x,y) (x < y ? x : y) diff --git a/src/cgame/cg_main.c b/src/cgame/cg_main.c index 6bd9d455..30eb134a 100644 --- a/src/cgame/cg_main.c +++ b/src/cgame/cg_main.c @@ -1054,7 +1054,7 @@ qboolean CG_Asset_Parse( int handle ) pc_token_t token; const char *tempStr; - if( !trap_PC_ReadToken( handle, &token ) ) + if( !trap_Parse_ReadToken( handle, &token ) ) return qfalse; if( Q_stricmp( token.string, "{" ) != 0 ) @@ -1062,7 +1062,7 @@ qboolean CG_Asset_Parse( int handle ) while( 1 ) { - if( !trap_PC_ReadToken( handle, &token ) ) + if( !trap_Parse_ReadToken( handle, &token ) ) return qfalse; if( Q_stricmp( token.string, "}" ) == 0 ) @@ -1221,17 +1221,17 @@ void CG_ParseMenu( const char *menuFile ) pc_token_t token; int handle; - handle = trap_PC_LoadSource( menuFile ); + handle = trap_Parse_LoadSource( menuFile ); if( !handle ) - handle = trap_PC_LoadSource( "ui/testhud.menu" ); + handle = trap_Parse_LoadSource( "ui/testhud.menu" ); if( !handle ) return; while( 1 ) { - if( !trap_PC_ReadToken( handle, &token ) ) + if( !trap_Parse_ReadToken( handle, &token ) ) break; //if ( Q_stricmp( token, "{" ) ) { @@ -1263,7 +1263,7 @@ void CG_ParseMenu( const char *menuFile ) } } - trap_PC_FreeSource( handle ); + trap_Parse_FreeSource( handle ); } qboolean CG_Load_Menu( char **p ) diff --git a/src/cgame/cg_public.h b/src/cgame/cg_public.h index 09f40d10..626f3201 100644 --- a/src/cgame/cg_public.h +++ b/src/cgame/cg_public.h @@ -138,11 +138,6 @@ typedef enum CG_KEY_GETCATCHER, CG_KEY_SETCATCHER, CG_KEY_GETKEY, - CG_PC_ADD_GLOBAL_DEFINE, - CG_PC_LOAD_SOURCE, - CG_PC_FREE_SOURCE, - CG_PC_READ_TOKEN, - CG_PC_SOURCE_FILE_AND_LINE, CG_S_STOPBACKGROUNDTRACK, CG_REAL_TIME, CG_SNAPVECTOR, @@ -177,6 +172,12 @@ typedef enum CG_KEY_GETBINDINGBUF, CG_KEY_SETBINDING, + CG_PARSE_ADD_GLOBAL_DEFINE, + CG_PARSE_LOAD_SOURCE, + CG_PARSE_FREE_SOURCE, + CG_PARSE_READ_TOKEN, + CG_PARSE_SOURCE_FILE_AND_LINE, + CG_MEMSET = 200, CG_MEMCPY, CG_STRNCPY, diff --git a/src/cgame/cg_syscalls.asm b/src/cgame/cg_syscalls.asm index 2fcc5296..0479f1d0 100644 --- a/src/cgame/cg_syscalls.asm +++ b/src/cgame/cg_syscalls.asm @@ -64,42 +64,43 @@ equ trap_Key_IsDown -61 equ trap_Key_GetCatcher -62 equ trap_Key_SetCatcher -63 equ trap_Key_GetKey -64 -equ trap_PC_AddGlobalDefine -65 -equ trap_PC_LoadSource -66 -equ trap_PC_FreeSource -67 -equ trap_PC_ReadToken -68 -equ trap_PC_SourceFileAndLine -69 -equ trap_S_StopBackgroundTrack -70 -equ trap_RealTime -71 -equ trap_SnapVector -72 -equ trap_RemoveCommand -73 -equ trap_R_LightForPoint -74 -equ trap_CIN_PlayCinematic -75 -equ trap_CIN_StopCinematic -76 -equ trap_CIN_RunCinematic -77 -equ trap_CIN_DrawCinematic -78 -equ trap_CIN_SetExtents -79 -equ trap_R_RemapShader -80 -equ trap_S_AddRealLoopingSound -81 -equ trap_S_StopLoopingSound -82 -equ trap_CM_TempCapsuleModel -83 -equ trap_CM_CapsuleTrace -84 -equ trap_CM_TransformedCapsuleTrace -85 -equ trap_R_AddAdditiveLightToScene -86 -equ trap_GetEntityToken -87 -equ trap_R_AddPolysToScene -88 -equ trap_R_inPVS -89 -equ trap_FS_Seek -90 -equ trap_FS_GetFileList -91 -equ trap_LiteralArgs -92 -equ trap_CM_BiSphereTrace -93 -equ trap_CM_TransformedBiSphereTrace -94 -equ trap_GetDemoState -95 -equ trap_GetDemoPos -96 -equ trap_GetDemoName -97 -equ trap_Key_KeynumToStringBuf -98 -equ trap_Key_GetBindingBuf -99 -equ trap_Key_SetBinding -100 +equ trap_S_StopBackgroundTrack -65 +equ trap_RealTime -66 +equ trap_SnapVector -67 +equ trap_RemoveCommand -68 +equ trap_R_LightForPoint -69 +equ trap_CIN_PlayCinematic -70 +equ trap_CIN_StopCinematic -71 +equ trap_CIN_RunCinematic -72 +equ trap_CIN_DrawCinematic -73 +equ trap_CIN_SetExtents -74 +equ trap_R_RemapShader -75 +equ trap_S_AddRealLoopingSound -76 +equ trap_S_StopLoopingSound -77 +equ trap_CM_TempCapsuleModel -78 +equ trap_CM_CapsuleTrace -79 +equ trap_CM_TransformedCapsuleTrace -80 +equ trap_R_AddAdditiveLightToScene -81 +equ trap_GetEntityToken -82 +equ trap_R_AddPolysToScene -83 +equ trap_R_inPVS -84 +equ trap_FS_Seek -85 +equ trap_FS_GetFileList -86 +equ trap_LiteralArgs -87 +equ trap_CM_BiSphereTrace -88 +equ trap_CM_TransformedBiSphereTrace -89 +equ trap_GetDemoState -90 +equ trap_GetDemoPos -91 +equ trap_GetDemoName -92 +equ trap_Key_KeynumToStringBuf -93 +equ trap_Key_GetBindingBuf -94 +equ trap_Key_SetBinding -95 + +equ trap_Parse_AddGlobalDefine -96 +equ trap_Parse_LoadSource -97 +equ trap_Parse_FreeSource -98 +equ trap_Parse_ReadToken -99 +equ trap_Parse_SourceFileAndLine -100 equ memset -201 equ memcpy -202 diff --git a/src/cgame/cg_syscalls.c b/src/cgame/cg_syscalls.c index 5c7ac16d..43afc2c4 100644 --- a/src/cgame/cg_syscalls.c +++ b/src/cgame/cg_syscalls.c @@ -467,29 +467,29 @@ int trap_Key_GetKey( const char *binding ) return syscall( CG_KEY_GETKEY, binding ); } -int trap_PC_AddGlobalDefine( char *define ) +int trap_Parse_AddGlobalDefine( char *define ) { - return syscall( CG_PC_ADD_GLOBAL_DEFINE, define ); + return syscall( CG_PARSE_ADD_GLOBAL_DEFINE, define ); } -int trap_PC_LoadSource( const char *filename ) +int trap_Parse_LoadSource( const char *filename ) { - return syscall( CG_PC_LOAD_SOURCE, filename ); + return syscall( CG_PARSE_LOAD_SOURCE, filename ); } -int trap_PC_FreeSource( int handle ) +int trap_Parse_FreeSource( int handle ) { - return syscall( CG_PC_FREE_SOURCE, handle ); + return syscall( CG_PARSE_FREE_SOURCE, handle ); } -int trap_PC_ReadToken( int handle, pc_token_t *pc_token ) +int trap_Parse_ReadToken( int handle, pc_token_t *pc_token ) { - return syscall( CG_PC_READ_TOKEN, handle, pc_token ); + return syscall( CG_PARSE_READ_TOKEN, handle, pc_token ); } -int trap_PC_SourceFileAndLine( int handle, char *filename, int *line ) +int trap_Parse_SourceFileAndLine( int handle, char *filename, int *line ) { - return syscall( CG_PC_SOURCE_FILE_AND_LINE, handle, filename, line ); + return syscall( CG_PARSE_SOURCE_FILE_AND_LINE, handle, filename, line ); } void trap_S_StopBackgroundTrack( void ) diff --git a/src/client/cl_cgame.c b/src/client/cl_cgame.c index 7d4c0a95..fd7c29ed 100644 --- a/src/client/cl_cgame.c +++ b/src/client/cl_cgame.c @@ -25,10 +25,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "client.h" -#include "../botlib/botlib.h" - -extern botlib_export_t *botlib_export; - extern qboolean loadCamera(const char *name); extern void startCamera(int time); extern qboolean getCameraInfo(int time, vec3_t *origin, vec3_t *angles); @@ -646,6 +642,16 @@ intptr_t CL_CgameSystemCalls( intptr_t *args ) { Key_SetBinding( args[1], VMA(2) ); return 0; + case CG_PARSE_ADD_GLOBAL_DEFINE: + return Parse_AddGlobalDefine( VMA(1) ); + case CG_PARSE_LOAD_SOURCE: + return Parse_LoadSourceHandle( VMA(1) ); + case CG_PARSE_FREE_SOURCE: + return Parse_FreeSourceHandle( args[1] ); + case CG_PARSE_READ_TOKEN: + return Parse_ReadTokenHandle( args[1], VMA(2) ); + case CG_PARSE_SOURCE_FILE_AND_LINE: + return Parse_SourceFileAndLine( args[1], VMA(2), VMA(3) ); case CG_MEMSET: Com_Memset( VMA(1), args[2], args[3] ); @@ -671,17 +677,6 @@ intptr_t CL_CgameSystemCalls( intptr_t *args ) { case CG_ACOS: return FloatAsInt( Q_acos( VMF(1) ) ); - case CG_PC_ADD_GLOBAL_DEFINE: - return botlib_export->PC_AddGlobalDefine( VMA(1) ); - case CG_PC_LOAD_SOURCE: - return botlib_export->PC_LoadSourceHandle( VMA(1) ); - case CG_PC_FREE_SOURCE: - return botlib_export->PC_FreeSourceHandle( args[1] ); - case CG_PC_READ_TOKEN: - return botlib_export->PC_ReadTokenHandle( args[1], VMA(2) ); - case CG_PC_SOURCE_FILE_AND_LINE: - return botlib_export->PC_SourceFileAndLine( args[1], VMA(2), VMA(3) ); - case CG_S_STOPBACKGROUNDTRACK: S_StopBackgroundTrack(); return 0; diff --git a/src/client/cl_ui.c b/src/client/cl_ui.c index d5dca4c2..327eaacf 100644 --- a/src/client/cl_ui.c +++ b/src/client/cl_ui.c @@ -23,10 +23,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "client.h" -#include "../botlib/botlib.h" - -extern botlib_export_t *botlib_export; - vm_t *uivm; /* @@ -958,16 +954,16 @@ intptr_t CL_UISystemCalls( intptr_t *args ) { case UI_CEIL: return FloatAsInt( ceil( VMF(1) ) ); - case UI_PC_ADD_GLOBAL_DEFINE: - return botlib_export->PC_AddGlobalDefine( VMA(1) ); - case UI_PC_LOAD_SOURCE: - return botlib_export->PC_LoadSourceHandle( VMA(1) ); - case UI_PC_FREE_SOURCE: - return botlib_export->PC_FreeSourceHandle( args[1] ); - case UI_PC_READ_TOKEN: - return botlib_export->PC_ReadTokenHandle( args[1], VMA(2) ); - case UI_PC_SOURCE_FILE_AND_LINE: - return botlib_export->PC_SourceFileAndLine( args[1], VMA(2), VMA(3) ); + case UI_PARSE_ADD_GLOBAL_DEFINE: + return Parse_AddGlobalDefine( VMA(1) ); + case UI_PARSE_LOAD_SOURCE: + return Parse_LoadSourceHandle( VMA(1) ); + case UI_PARSE_FREE_SOURCE: + return Parse_FreeSourceHandle( args[1] ); + case UI_PARSE_READ_TOKEN: + return Parse_ReadTokenHandle( args[1], VMA(2) ); + case UI_PARSE_SOURCE_FILE_AND_LINE: + return Parse_SourceFileAndLine( args[1], VMA(2), VMA(3) ); case UI_S_STOPBACKGROUNDTRACK: S_StopBackgroundTrack(); diff --git a/src/game/g_active.c b/src/game/g_active.c index d78d4b98..99d4c308 100644 --- a/src/game/g_active.c +++ b/src/game/g_active.c @@ -217,9 +217,6 @@ void ClientImpacts( gentity_t *ent, pmove_t *pm ) other = &g_entities[ pm->touchents[ i ] ]; - if( ( ent->r.svFlags & SVF_BOT ) && ( ent->touch ) ) - ent->touch( ent, other, &trace ); - //charge attack if( ent->client->ps.weapon == WP_ALEVEL4 && ent->client->ps.stats[ STAT_MISC ] > 0 && @@ -306,9 +303,6 @@ void G_TouchTriggers( gentity_t *ent ) if( hit->touch ) hit->touch( hit, ent, &trace ); - - if( ( ent->r.svFlags & SVF_BOT ) && ( ent->touch ) ) - ent->touch( ent, hit, &trace ); } // if we didn't touch a jump pad this pmove frame @@ -1415,14 +1409,14 @@ void ClientThink( int clientNum ) // phone jack if they don't get any for a while ent->client->lastCmdTime = level.time; - if( !(ent->r.svFlags & SVF_BOT) && !g_synchronousClients.integer ) + if( !g_synchronousClients.integer ) ClientThink_real( ent ); } void G_RunClient( gentity_t *ent ) { - if( !( ent->r.svFlags & SVF_BOT ) && !g_synchronousClients.integer ) + if( !g_synchronousClients.integer ) return; ent->client->pers.cmd.serverTime = level.time; diff --git a/src/game/g_client.c b/src/game/g_client.c index f95b23af..b80451f3 100644 --- a/src/game/g_client.c +++ b/src/game/g_client.c @@ -1117,7 +1117,7 @@ to the server machine, but qfalse on map changes and tournement restarts. ============ */ -char *ClientConnect( int clientNum, qboolean firstTime, qboolean isBot ) +char *ClientConnect( int clientNum, qboolean firstTime ) { char *value; gclient_t *client; diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c index e881ad4e..6ce2d657 100644 --- a/src/game/g_cmds.c +++ b/src/game/g_cmds.c @@ -691,7 +691,7 @@ static void Cmd_Tell_f( gentity_t *ent ) G_Say( ent, target, SAY_TELL, p ); // don't tell to the player self if it was already directed to this player // also don't send the chat back to a bot - if( ent != target && !( ent->r.svFlags & SVF_BOT ) ) + if( ent != target ) G_Say( ent, ent, SAY_TELL, p ); } @@ -2054,7 +2054,6 @@ void G_StopFollowing( gentity_t *ent ) ent->client->ps.eFlags &= ~EF_WALLCLIMB; ent->client->ps.viewangles[ PITCH ] = 0.0f; - ent->r.svFlags &= ~SVF_BOT; ent->client->ps.clientNum = ent - g_entities; CalculateRanks( ); diff --git a/src/game/g_local.h b/src/game/g_local.h index a6009908..2dd36dc3 100644 --- a/src/game/g_local.h +++ b/src/game/g_local.h @@ -876,7 +876,7 @@ void QDECL G_Error( const char *fmt, ... ); // // g_client.c // -char *ClientConnect( int clientNum, qboolean firstTime, qboolean isBot ); +char *ClientConnect( int clientNum, qboolean firstTime ); void ClientUserinfoChanged( int clientNum ); void ClientDisconnect( int clientNum ); void ClientBegin( int clientNum ); @@ -1123,8 +1123,5 @@ void trap_BotFreeClient( int clientNum ); void trap_GetUsercmd( int clientNum, usercmd_t *cmd ); qboolean trap_GetEntityToken( char *buffer, int bufferSize ); -int trap_DebugPolygonCreate(int color, int numPoints, vec3_t *points); -void trap_DebugPolygonDelete(int id); - void trap_SnapVector( float *v ); void trap_SendGameStat( const char *data ); diff --git a/src/game/g_main.c b/src/game/g_main.c index 5fca0584..c8fd701b 100644 --- a/src/game/g_main.c +++ b/src/game/g_main.c @@ -240,7 +240,7 @@ intptr_t vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4, return 0; case GAME_CLIENT_CONNECT: - return (intptr_t)ClientConnect( arg0, arg1, arg2 ); + return (intptr_t)ClientConnect( arg0, arg1 ); case GAME_CLIENT_THINK: ClientThink( arg0 ); @@ -1197,8 +1197,7 @@ void CalculateRanks( void ) if( level.clients[ i ].pers.connected == CON_CONNECTED ) { level.numPlayingClients++; - if( !(g_entities[ i ].r.svFlags & SVF_BOT) ) - level.numVotingClients++; + level.numVotingClients++; if( level.clients[ i ].ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) level.numteamVotingClients[ 0 ]++; @@ -1646,9 +1645,6 @@ void CheckIntermissionExit( void ) if( cl->ps.stats[ STAT_PTEAM ] == PTE_NONE ) continue; - if( g_entities[ cl->ps.clientNum ].r.svFlags & SVF_BOT ) - continue; - if( cl->readyToExit ) { ready++; diff --git a/src/game/g_public.h b/src/game/g_public.h index ba7a6e69..fc6b7df3 100644 --- a/src/game/g_public.h +++ b/src/game/g_public.h @@ -35,7 +35,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=551 #define SVF_CLIENTMASK 0x00000002 -#define SVF_BOT 0x00000008 #define SVF_BROADCAST 0x00000020 // send to all connected clients #define SVF_PORTAL 0x00000040 // merge a second pvs at origin2 into snapshots #define SVF_USE_CURRENT_ORIGIN 0x00000080 // entity->r.currentOrigin instead of entity->s.origin @@ -200,11 +199,6 @@ typedef enum { G_ENTITY_CONTACT, // ( const vec3_t mins, const vec3_t maxs, const gentity_t *ent ); // perform an exact check against inline brush models of non-square shape - // access for bots to get and free a server client (FIXME?) - G_BOT_ALLOCATE_CLIENT, // ( void ); - - G_BOT_FREE_CLIENT, // ( int clientNum ); - G_GET_USERCMD, // ( int clientNum, usercmd_t *cmd ) G_GET_ENTITY_TOKEN, // qboolean ( char *buffer, int bufferSize ) @@ -213,8 +207,6 @@ typedef enum { // This should only be done at GAME_INIT time. G_FS_GETFILELIST, - G_DEBUG_POLYGON_CREATE, - G_DEBUG_POLYGON_DELETE, G_REAL_TIME, G_SNAPVECTOR, @@ -224,169 +216,13 @@ typedef enum { // 1.32 G_FS_SEEK, - G_SEND_GAMESTAT, - - BOTLIB_SETUP = 200, // ( void ); - BOTLIB_SHUTDOWN, // ( void ); - BOTLIB_LIBVAR_SET, - BOTLIB_LIBVAR_GET, - BOTLIB_PC_ADD_GLOBAL_DEFINE, - BOTLIB_START_FRAME, - BOTLIB_LOAD_MAP, - BOTLIB_UPDATENTITY, - BOTLIB_TEST, - - BOTLIB_GET_SNAPSHOT_ENTITY, // ( int client, int ent ); - BOTLIB_GET_CONSOLE_MESSAGE, // ( int client, char *message, int size ); - BOTLIB_USER_COMMAND, // ( int client, usercmd_t *ucmd ); - - BOTLIB_AAS_ENABLE_ROUTING_AREA = 300, - BOTLIB_AAS_BBOX_AREAS, - BOTLIB_AAS_AREA_INFO, - BOTLIB_AAS_ENTITY_INFO, - - BOTLIB_AAS_INITIALIZED, - BOTLIB_AAS_PRESENCE_TYPE_BOUNDING_BOX, - BOTLIB_AAS_TIME, - - BOTLIB_AAS_POINT_AREA_NUM, - BOTLIB_AAS_TRACE_AREAS, - - BOTLIB_AAS_POINT_CONTENTS, - BOTLIB_AAS_NEXT_BSP_ENTITY, - BOTLIB_AAS_VALUE_FOR_BSP_EPAIR_KEY, - BOTLIB_AAS_VECTOR_FOR_BSP_EPAIR_KEY, - BOTLIB_AAS_FLOAT_FOR_BSP_EPAIR_KEY, - BOTLIB_AAS_INT_FOR_BSP_EPAIR_KEY, - - BOTLIB_AAS_AREA_REACHABILITY, - - BOTLIB_AAS_AREA_TRAVEL_TIME_TO_GOAL_AREA, - - BOTLIB_AAS_SWIMMING, - BOTLIB_AAS_PREDICT_CLIENT_MOVEMENT, - - - - BOTLIB_EA_SAY = 400, - BOTLIB_EA_SAY_TEAM, - BOTLIB_EA_COMMAND, - - BOTLIB_EA_ACTION, - BOTLIB_EA_GESTURE, - BOTLIB_EA_TALK, - BOTLIB_EA_ATTACK, - BOTLIB_EA_USE, - BOTLIB_EA_RESPAWN, - BOTLIB_EA_CROUCH, - BOTLIB_EA_MOVE_UP, - BOTLIB_EA_MOVE_DOWN, - BOTLIB_EA_MOVE_FORWARD, - BOTLIB_EA_MOVE_BACK, - BOTLIB_EA_MOVE_LEFT, - BOTLIB_EA_MOVE_RIGHT, - - BOTLIB_EA_SELECT_WEAPON, - BOTLIB_EA_JUMP, - BOTLIB_EA_DELAYED_JUMP, - BOTLIB_EA_MOVE, - BOTLIB_EA_VIEW, - - BOTLIB_EA_END_REGULAR, - BOTLIB_EA_GET_INPUT, - BOTLIB_EA_RESET_INPUT, - - - - BOTLIB_AI_LOAD_CHARACTER = 500, - BOTLIB_AI_FREE_CHARACTER, - BOTLIB_AI_CHARACTERISTIC_FLOAT, - BOTLIB_AI_CHARACTERISTIC_BFLOAT, - BOTLIB_AI_CHARACTERISTIC_INTEGER, - BOTLIB_AI_CHARACTERISTIC_BINTEGER, - BOTLIB_AI_CHARACTERISTIC_STRING, - - BOTLIB_AI_ALLOC_CHAT_STATE, - BOTLIB_AI_FREE_CHAT_STATE, - BOTLIB_AI_QUEUE_CONSOLE_MESSAGE, - BOTLIB_AI_REMOVE_CONSOLE_MESSAGE, - BOTLIB_AI_NEXT_CONSOLE_MESSAGE, - BOTLIB_AI_NUM_CONSOLE_MESSAGE, - BOTLIB_AI_INITIAL_CHAT, - BOTLIB_AI_REPLY_CHAT, - BOTLIB_AI_CHAT_LENGTH, - BOTLIB_AI_ENTER_CHAT, - BOTLIB_AI_STRING_CONTAINS, - BOTLIB_AI_FIND_MATCH, - BOTLIB_AI_MATCH_VARIABLE, - BOTLIB_AI_UNIFY_WHITE_SPACES, - BOTLIB_AI_REPLACE_SYNONYMS, - BOTLIB_AI_LOAD_CHAT_FILE, - BOTLIB_AI_SET_CHAT_GENDER, - BOTLIB_AI_SET_CHAT_NAME, - - BOTLIB_AI_RESET_GOAL_STATE, - BOTLIB_AI_RESET_AVOID_GOALS, - BOTLIB_AI_PUSH_GOAL, - BOTLIB_AI_POP_GOAL, - BOTLIB_AI_EMPTY_GOAL_STACK, - BOTLIB_AI_DUMP_AVOID_GOALS, - BOTLIB_AI_DUMP_GOAL_STACK, - BOTLIB_AI_GOAL_NAME, - BOTLIB_AI_GET_TOP_GOAL, - BOTLIB_AI_GET_SECOND_GOAL, - BOTLIB_AI_CHOOSE_LTG_ITEM, - BOTLIB_AI_CHOOSE_NBG_ITEM, - BOTLIB_AI_TOUCHING_GOAL, - BOTLIB_AI_ITEM_GOAL_IN_VIS_BUT_NOT_VISIBLE, - BOTLIB_AI_GET_LEVEL_ITEM_GOAL, - BOTLIB_AI_AVOID_GOAL_TIME, - BOTLIB_AI_INIT_LEVEL_ITEMS, - BOTLIB_AI_UPDATE_ENTITY_ITEMS, - BOTLIB_AI_LOAD_ITEM_WEIGHTS, - BOTLIB_AI_FREE_ITEM_WEIGHTS, - BOTLIB_AI_SAVE_GOAL_FUZZY_LOGIC, - BOTLIB_AI_ALLOC_GOAL_STATE, - BOTLIB_AI_FREE_GOAL_STATE, - - BOTLIB_AI_RESET_MOVE_STATE, - BOTLIB_AI_MOVE_TO_GOAL, - BOTLIB_AI_MOVE_IN_DIRECTION, - BOTLIB_AI_RESET_AVOID_REACH, - BOTLIB_AI_RESET_LAST_AVOID_REACH, - BOTLIB_AI_REACHABILITY_AREA, - BOTLIB_AI_MOVEMENT_VIEW_TARGET, - BOTLIB_AI_ALLOC_MOVE_STATE, - BOTLIB_AI_FREE_MOVE_STATE, - BOTLIB_AI_INIT_MOVE_STATE, - - BOTLIB_AI_CHOOSE_BEST_FIGHT_WEAPON, - BOTLIB_AI_GET_WEAPON_INFO, - BOTLIB_AI_LOAD_WEAPON_WEIGHTS, - BOTLIB_AI_ALLOC_WEAPON_STATE, - BOTLIB_AI_FREE_WEAPON_STATE, - BOTLIB_AI_RESET_WEAPON_STATE, - - BOTLIB_AI_GENETIC_PARENTS_AND_CHILD_SELECTION, - BOTLIB_AI_INTERBREED_GOAL_FUZZY_LOGIC, - BOTLIB_AI_MUTATE_GOAL_FUZZY_LOGIC, - BOTLIB_AI_GET_NEXT_CAMP_SPOT_GOAL, - BOTLIB_AI_GET_MAP_LOCATION_GOAL, - BOTLIB_AI_NUM_INITIAL_CHATS, - BOTLIB_AI_GET_CHAT_MESSAGE, - BOTLIB_AI_REMOVE_FROM_AVOID_GOALS, - BOTLIB_AI_PREDICT_VISIBLE_POSITION, - - BOTLIB_AI_SET_AVOID_GOAL_TIME, - BOTLIB_AI_ADD_AVOID_SPOT, - BOTLIB_AAS_ALTERNATIVE_ROUTE_GOAL, - BOTLIB_AAS_PREDICT_ROUTE, - BOTLIB_AAS_POINT_REACHABILITY_AREA_INDEX, - - BOTLIB_PC_LOAD_SOURCE, - BOTLIB_PC_FREE_SOURCE, - BOTLIB_PC_READ_TOKEN, - BOTLIB_PC_SOURCE_FILE_AND_LINE + G_PARSE_ADD_GLOBAL_DEFINE, + G_PARSE_LOAD_SOURCE, + G_PARSE_FREE_SOURCE, + G_PARSE_READ_TOKEN, + G_PARSE_SOURCE_FILE_AND_LINE, + + G_SEND_GAMESTAT } gameImport_t; @@ -401,7 +237,7 @@ typedef enum { GAME_SHUTDOWN, // (void); - GAME_CLIENT_CONNECT, // ( int clientNum, qboolean firstTime, qboolean isBot ); + GAME_CLIENT_CONNECT, // ( int clientNum, qboolean firstTime ); // return NULL if the client is allowed to connect, otherwise return // a text string with the reason for denial @@ -417,12 +253,10 @@ typedef enum { GAME_RUN_FRAME, // ( int levelTime ); - GAME_CONSOLE_COMMAND, // ( void ); + GAME_CONSOLE_COMMAND // ( void ); // ConsoleCommand will be called when a command has been issued // that is not recognized as a builtin function. // The game can issue trap_argc() / trap_argv() commands to get the command // and parameters. Return qfalse if the game doesn't recognize it as a command. - - BOTAI_START_FRAME // ( int time ); } gameExport_t; diff --git a/src/game/g_syscalls.asm b/src/game/g_syscalls.asm index fda100a0..79a9b3d6 100644 --- a/src/game/g_syscalls.asm +++ b/src/game/g_syscalls.asm @@ -34,29 +34,19 @@ equ trap_LinkEntity -31 equ trap_UnlinkEntity -32 equ trap_EntitiesInBox -33 equ trap_EntityContact -34 -equ trap_BotAllocateClient -35 -equ trap_BotFreeClient -36 -equ trap_GetUsercmd -37 -equ trap_GetEntityToken -38 -equ trap_FS_GetFileList -39 -equ trap_DebugPolygonCreate -40 -equ trap_DebugPolygonDelete -41 -equ trap_RealTime -42 -equ trap_SnapVector -43 -equ trap_TraceCapsule -44 -equ trap_EntityContactCapsule -45 -equ trap_FS_Seek -46 -equ trap_SendGameStat -47 +equ trap_GetUsercmd -35 +equ trap_GetEntityToken -36 +equ trap_FS_GetFileList -37 +equ trap_RealTime -38 +equ trap_SnapVector -39 +equ trap_TraceCapsule -40 +equ trap_EntityContactCapsule -41 +equ trap_FS_Seek -42 +equ trap_Parse_AddGlobalDefine -43 +equ trap_Parse_LoadSource -44 +equ trap_Parse_FreeSource -45 +equ trap_Parse_ReadToken -46 +equ trap_Parse_SourceFileAndLine -47 -equ memset -101 -equ memcpy -102 -equ strncpy -103 -equ sin -104 -equ cos -105 -equ atan2 -106 -equ sqrt -107 -equ floor -111 -equ ceil -112 -equ testPrintInt -113 -equ testPrintFloat -114 +equ trap_SendGameStat -48 diff --git a/src/game/g_syscalls.c b/src/game/g_syscalls.c index b6347441..cb4ceb66 100644 --- a/src/game/g_syscalls.c +++ b/src/game/g_syscalls.c @@ -229,15 +229,6 @@ qboolean trap_EntityContactCapsule( const vec3_t mins, const vec3_t maxs, const { return syscall( G_ENTITY_CONTACTCAPSULE, mins, maxs, ent ); } -int trap_BotAllocateClient( void ) -{ - return syscall( G_BOT_ALLOCATE_CLIENT ); -} - -void trap_BotFreeClient( int clientNum ) -{ - syscall( G_BOT_FREE_CLIENT, clientNum ); -} void trap_GetUsercmd( int clientNum, usercmd_t *cmd ) { @@ -249,16 +240,6 @@ qboolean trap_GetEntityToken( char *buffer, int bufferSize ) return syscall( G_GET_ENTITY_TOKEN, buffer, bufferSize ); } -int trap_DebugPolygonCreate(int color, int numPoints, vec3_t *points) -{ - return syscall( G_DEBUG_POLYGON_CREATE, color, numPoints, points ); -} - -void trap_DebugPolygonDelete(int id) -{ - syscall( G_DEBUG_POLYGON_DELETE, id ); -} - int trap_RealTime( qtime_t *qtime ) { return syscall( G_REAL_TIME, qtime ); @@ -275,3 +256,29 @@ void trap_SendGameStat( const char *data ) syscall( G_SEND_GAMESTAT, data ); return; } + +int trap_Parse_AddGlobalDefine( char *define ) +{ + return syscall( G_PARSE_ADD_GLOBAL_DEFINE, define ); +} + +int trap_Parse_LoadSource( const char *filename ) +{ + return syscall( G_PARSE_LOAD_SOURCE, filename ); +} + +int trap_Parse_FreeSource( int handle ) +{ + return syscall( G_PARSE_FREE_SOURCE, handle ); +} + +int trap_Parse_ReadToken( int handle, pc_token_t *pc_token ) +{ + return syscall( G_PARSE_READ_TOKEN, handle, pc_token ); +} + +int trap_Parse_SourceFileAndLine( int handle, char *filename, int *line ) +{ + return syscall( G_PARSE_SOURCE_FILE_AND_LINE, handle, filename, line ); +} + diff --git a/src/game/g_utils.c b/src/game/g_utils.c index 9caaba76..a3b2cb42 100644 --- a/src/game/g_utils.c +++ b/src/game/g_utils.c @@ -837,45 +837,3 @@ void G_CloseMenus( int clientNum ) Com_sprintf( buffer, 32, "serverclosemenus" ); trap_SendServerCommand( clientNum, buffer ); } - - -/* -================ -DebugLine - - debug polygons only work when running a local game - with r_debugSurface set to 2 -================ -*/ -int DebugLine( vec3_t start, vec3_t end, int color ) -{ - vec3_t points[ 4 ], dir, cross, up = { 0, 0, 1 }; - float dot; - - VectorCopy( start, points[ 0 ] ); - VectorCopy( start, points[ 1 ] ); - //points[1][2] -= 2; - VectorCopy( end, points[ 2 ] ); - //points[2][2] -= 2; - VectorCopy( end, points[ 3 ] ); - - - VectorSubtract( end, start, dir ); - VectorNormalize( dir ); - dot = DotProduct( dir, up ); - - if( dot > 0.99 || dot < -0.99 ) - VectorSet( cross, 1, 0, 0 ); - else - CrossProduct( dir, up, cross ); - - VectorNormalize( cross ); - - VectorMA(points[ 0 ], 2, cross, points[ 0 ] ); - VectorMA(points[ 1 ], -2, cross, points[ 1 ] ); - VectorMA(points[ 2 ], -2, cross, points[ 2 ] ); - VectorMA(points[ 3 ], 2, cross, points[ 3 ] ); - - return trap_DebugPolygonCreate( color, 4, points ); -} - diff --git a/src/qcommon/cm_patch.c b/src/qcommon/cm_patch.c index 194b806c..f262db9c 100644 --- a/src/qcommon/cm_patch.c +++ b/src/qcommon/cm_patch.c @@ -1611,10 +1611,6 @@ CM_DrawDebugSurface Called from the renderer ================== */ -#ifndef BSPC -void BotDrawDebugPolygons(void (*drawPoly)(int color, int numPoints, float *points), int value); -#endif - void CM_DrawDebugSurface( void (*drawPoly)(int color, int numPoints, float *points) ) { static cvar_t *cv; #ifndef BSPC @@ -1638,7 +1634,6 @@ void CM_DrawDebugSurface( void (*drawPoly)(int color, int numPoints, float *poin if (cv2->integer != 1) { - BotDrawDebugPolygons(drawPoly, cv2->integer); return; } #endif diff --git a/src/qcommon/net_chan.c b/src/qcommon/net_chan.c index 3bf6a561..4df95c46 100644 --- a/src/qcommon/net_chan.c +++ b/src/qcommon/net_chan.c @@ -502,8 +502,6 @@ const char *NET_AdrToString (netadr_t a) if (a.type == NA_LOOPBACK) { Com_sprintf (s, sizeof(s), "loopback"); - } else if (a.type == NA_BOT) { - Com_sprintf (s, sizeof(s), "bot"); } else if (a.type == NA_IP) { Com_sprintf (s, sizeof(s), "%i.%i.%i.%i:%hu", a.ip[0], a.ip[1], a.ip[2], a.ip[3], BigShort(a.port)); @@ -628,9 +626,6 @@ void NET_SendPacket( netsrc_t sock, int length, const void *data, netadr_t to ) NET_SendLoopPacket (sock, length, data, to); return; } - if ( to.type == NA_BOT ) { - return; - } if ( to.type == NA_BAD ) { return; } diff --git a/src/qcommon/parse.c b/src/qcommon/parse.c new file mode 100644 index 00000000..136ba0b1 --- /dev/null +++ b/src/qcommon/parse.c @@ -0,0 +1,3585 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. +Copyright (C) 2000-2006 Tim Angus + +This file is part of Tremulous. + +Tremulous is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Tremulous is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Tremulous; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "q_shared.h" +#include "qcommon.h" + +//script flags +#define SCFL_NOERRORS 0x0001 +#define SCFL_NOWARNINGS 0x0002 +#define SCFL_NOSTRINGWHITESPACES 0x0004 +#define SCFL_NOSTRINGESCAPECHARS 0x0008 +#define SCFL_PRIMITIVE 0x0010 +#define SCFL_NOBINARYNUMBERS 0x0020 +#define SCFL_NONUMBERVALUES 0x0040 + +//token types +#define TT_STRING 1 // string +#define TT_LITERAL 2 // literal +#define TT_NUMBER 3 // number +#define TT_NAME 4 // name +#define TT_PUNCTUATION 5 // punctuation + +//string sub type +//--------------- +// the length of the string +//literal sub type +//---------------- +// the ASCII code of the literal +//number sub type +//--------------- +#define TT_DECIMAL 0x0008 // decimal number +#define TT_HEX 0x0100 // hexadecimal number +#define TT_OCTAL 0x0200 // octal number +#define TT_BINARY 0x0400 // binary number +#define TT_FLOAT 0x0800 // floating point number +#define TT_INTEGER 0x1000 // integer number +#define TT_LONG 0x2000 // long number +#define TT_UNSIGNED 0x4000 // unsigned number +//punctuation sub type +//-------------------- +#define P_RSHIFT_ASSIGN 1 +#define P_LSHIFT_ASSIGN 2 +#define P_PARMS 3 +#define P_PRECOMPMERGE 4 + +#define P_LOGIC_AND 5 +#define P_LOGIC_OR 6 +#define P_LOGIC_GEQ 7 +#define P_LOGIC_LEQ 8 +#define P_LOGIC_EQ 9 +#define P_LOGIC_UNEQ 10 + +#define P_MUL_ASSIGN 11 +#define P_DIV_ASSIGN 12 +#define P_MOD_ASSIGN 13 +#define P_ADD_ASSIGN 14 +#define P_SUB_ASSIGN 15 +#define P_INC 16 +#define P_DEC 17 + +#define P_BIN_AND_ASSIGN 18 +#define P_BIN_OR_ASSIGN 19 +#define P_BIN_XOR_ASSIGN 20 +#define P_RSHIFT 21 +#define P_LSHIFT 22 + +#define P_POINTERREF 23 +#define P_CPP1 24 +#define P_CPP2 25 +#define P_MUL 26 +#define P_DIV 27 +#define P_MOD 28 +#define P_ADD 29 +#define P_SUB 30 +#define P_ASSIGN 31 + +#define P_BIN_AND 32 +#define P_BIN_OR 33 +#define P_BIN_XOR 34 +#define P_BIN_NOT 35 + +#define P_LOGIC_NOT 36 +#define P_LOGIC_GREATER 37 +#define P_LOGIC_LESS 38 + +#define P_REF 39 +#define P_COMMA 40 +#define P_SEMICOLON 41 +#define P_COLON 42 +#define P_QUESTIONMARK 43 + +#define P_PARENTHESESOPEN 44 +#define P_PARENTHESESCLOSE 45 +#define P_BRACEOPEN 46 +#define P_BRACECLOSE 47 +#define P_SQBRACKETOPEN 48 +#define P_SQBRACKETCLOSE 49 +#define P_BACKSLASH 50 + +#define P_PRECOMP 51 +#define P_DOLLAR 52 + +//name sub type +//------------- +// the length of the name + +//punctuation +typedef struct punctuation_s +{ + char *p; //punctuation character(s) + int n; //punctuation indication + struct punctuation_s *next; //next punctuation +} punctuation_t; + +//token +typedef struct token_s +{ + char string[MAX_TOKEN_CHARS]; //available token + int type; //last read token type + int subtype; //last read token sub type + unsigned long int intvalue; //integer value + double floatvalue; //floating point value + char *whitespace_p; //start of white space before token + char *endwhitespace_p; //start of white space before token + int line; //line the token was on + int linescrossed; //lines crossed in white space + struct token_s *next; //next token in chain +} token_t; + +//script file +typedef struct script_s +{ + char filename[1024]; //file name of the script + char *buffer; //buffer containing the script + char *script_p; //current pointer in the script + char *end_p; //pointer to the end of the script + char *lastscript_p; //script pointer before reading token + char *whitespace_p; //begin of the white space + char *endwhitespace_p; + int length; //length of the script in bytes + int line; //current line in script + int lastline; //line before reading token + int tokenavailable; //set by UnreadLastToken + int flags; //several script flags + punctuation_t *punctuations; //the punctuations used in the script + punctuation_t **punctuationtable; + token_t token; //available token + struct script_s *next; //next script in a chain +} script_t; + + +#define DEFINE_FIXED 0x0001 + +#define BUILTIN_LINE 1 +#define BUILTIN_FILE 2 +#define BUILTIN_DATE 3 +#define BUILTIN_TIME 4 +#define BUILTIN_STDC 5 + +#define INDENT_IF 0x0001 +#define INDENT_ELSE 0x0002 +#define INDENT_ELIF 0x0004 +#define INDENT_IFDEF 0x0008 +#define INDENT_IFNDEF 0x0010 + +//macro definitions +typedef struct define_s +{ + char *name; //define name + int flags; //define flags + int builtin; // > 0 if builtin define + int numparms; //number of define parameters + token_t *parms; //define parameters + token_t *tokens; //macro tokens (possibly containing parm tokens) + struct define_s *next; //next defined macro in a list + struct define_s *hashnext; //next define in the hash chain +} define_t; + +//indents +//used for conditional compilation directives: +//#if, #else, #elif, #ifdef, #ifndef +typedef struct indent_s +{ + int type; //indent type + int skip; //true if skipping current indent + script_t *script; //script the indent was in + struct indent_s *next; //next indent on the indent stack +} indent_t; + +//source file +typedef struct source_s +{ + char filename[MAX_QPATH]; //file name of the script + char includepath[MAX_QPATH]; //path to include files + punctuation_t *punctuations; //punctuations to use + script_t *scriptstack; //stack with scripts of the source + token_t *tokens; //tokens to read first + define_t *defines; //list with macro definitions + define_t **definehash; //hash chain with defines + indent_t *indentstack; //stack with indents + int skip; // > 0 if skipping conditional code + token_t token; //last read token +} source_t; + +#define MAX_DEFINEPARMS 128 + +//directive name with parse function +typedef struct directive_s +{ + char *name; + int (*func)(source_t *source); +} directive_t; + +#define DEFINEHASHSIZE 1024 + +static int Parse_ReadToken(source_t *source, token_t *token); + +int numtokens; + +//list with global defines added to every source loaded +define_t *globaldefines; + +//longer punctuations first +punctuation_t default_punctuations[] = +{ + //binary operators + {">>=",P_RSHIFT_ASSIGN, NULL}, + {"<<=",P_LSHIFT_ASSIGN, NULL}, + // + {"...",P_PARMS, NULL}, + //define merge operator + {"##",P_PRECOMPMERGE, NULL}, + //logic operators + {"&&",P_LOGIC_AND, NULL}, + {"||",P_LOGIC_OR, NULL}, + {">=",P_LOGIC_GEQ, NULL}, + {"<=",P_LOGIC_LEQ, NULL}, + {"==",P_LOGIC_EQ, NULL}, + {"!=",P_LOGIC_UNEQ, NULL}, + //arithmatic operators + {"*=",P_MUL_ASSIGN, NULL}, + {"/=",P_DIV_ASSIGN, NULL}, + {"%=",P_MOD_ASSIGN, NULL}, + {"+=",P_ADD_ASSIGN, NULL}, + {"-=",P_SUB_ASSIGN, NULL}, + {"++",P_INC, NULL}, + {"--",P_DEC, NULL}, + //binary operators + {"&=",P_BIN_AND_ASSIGN, NULL}, + {"|=",P_BIN_OR_ASSIGN, NULL}, + {"^=",P_BIN_XOR_ASSIGN, NULL}, + {">>",P_RSHIFT, NULL}, + {"<<",P_LSHIFT, NULL}, + //reference operators + {"->",P_POINTERREF, NULL}, + //C++ + {"::",P_CPP1, NULL}, + {".*",P_CPP2, NULL}, + //arithmatic operators + {"*",P_MUL, NULL}, + {"/",P_DIV, NULL}, + {"%",P_MOD, NULL}, + {"+",P_ADD, NULL}, + {"-",P_SUB, NULL}, + {"=",P_ASSIGN, NULL}, + //binary operators + {"&",P_BIN_AND, NULL}, + {"|",P_BIN_OR, NULL}, + {"^",P_BIN_XOR, NULL}, + {"~",P_BIN_NOT, NULL}, + //logic operators + {"!",P_LOGIC_NOT, NULL}, + {">",P_LOGIC_GREATER, NULL}, + {"<",P_LOGIC_LESS, NULL}, + //reference operator + {".",P_REF, NULL}, + //seperators + {",",P_COMMA, NULL}, + {";",P_SEMICOLON, NULL}, + //label indication + {":",P_COLON, NULL}, + //if statement + {"?",P_QUESTIONMARK, NULL}, + //embracements + {"(",P_PARENTHESESOPEN, NULL}, + {")",P_PARENTHESESCLOSE, NULL}, + {"{",P_BRACEOPEN, NULL}, + {"}",P_BRACECLOSE, NULL}, + {"[",P_SQBRACKETOPEN, NULL}, + {"]",P_SQBRACKETCLOSE, NULL}, + // + {"\\",P_BACKSLASH, NULL}, + //precompiler operator + {"#",P_PRECOMP, NULL}, + {"$",P_DOLLAR, NULL}, + {NULL, 0} +}; + +char basefolder[MAX_QPATH]; + +/* +=============== +Parse_CreatePunctuationTable +=============== +*/ +static void Parse_CreatePunctuationTable(script_t *script, punctuation_t *punctuations) +{ + int i; + punctuation_t *p, *lastp, *newp; + + //get memory for the table + if (!script->punctuationtable) script->punctuationtable = (punctuation_t **) + Z_Malloc(256 * sizeof(punctuation_t *)); + Com_Memset(script->punctuationtable, 0, 256 * sizeof(punctuation_t *)); + //add the punctuations in the list to the punctuation table + for (i = 0; punctuations[i].p; i++) + { + newp = &punctuations[i]; + lastp = NULL; + //sort the punctuations in this table entry on length (longer punctuations first) + for (p = script->punctuationtable[(unsigned int) newp->p[0]]; p; p = p->next) + { + if (strlen(p->p) < strlen(newp->p)) + { + newp->next = p; + if (lastp) lastp->next = newp; + else script->punctuationtable[(unsigned int) newp->p[0]] = newp; + break; + } + lastp = p; + } + if (!p) + { + newp->next = NULL; + if (lastp) lastp->next = newp; + else script->punctuationtable[(unsigned int) newp->p[0]] = newp; + } + } +} + +/* +=============== +Parse_ScriptError +=============== +*/ +static void QDECL Parse_ScriptError(script_t *script, char *str, ...) +{ + char text[1024]; + va_list ap; + + if (script->flags & SCFL_NOERRORS) return; + + va_start(ap, str); + vsprintf(text, str, ap); + va_end(ap); + Com_Printf( "file %s, line %d: %s\n", script->filename, script->line, text); +} + +/* +=============== +Parse_ScriptWarning +=============== +*/ +static void QDECL Parse_ScriptWarning(script_t *script, char *str, ...) +{ + char text[1024]; + va_list ap; + + if (script->flags & SCFL_NOWARNINGS) return; + + va_start(ap, str); + vsprintf(text, str, ap); + va_end(ap); + Com_Printf( "file %s, line %d: %s\n", script->filename, script->line, text); +} + +/* +=============== +Parse_SetScriptPunctuations +=============== +*/ +static void Parse_SetScriptPunctuations(script_t *script, punctuation_t *p) +{ + if (p) Parse_CreatePunctuationTable(script, p); + else Parse_CreatePunctuationTable(script, default_punctuations); + if (p) script->punctuations = p; + else script->punctuations = default_punctuations; +} + +/* +=============== +Parse_ReadWhiteSpace +=============== +*/ +static int Parse_ReadWhiteSpace(script_t *script) +{ + while(1) + { + //skip white space + while(*script->script_p <= ' ') + { + if (!*script->script_p) return 0; + if (*script->script_p == '\n') script->line++; + script->script_p++; + } + //skip comments + if (*script->script_p == '/') + { + //comments // + if (*(script->script_p+1) == '/') + { + script->script_p++; + do + { + script->script_p++; + if (!*script->script_p) return 0; + } + while(*script->script_p != '\n'); + script->line++; + script->script_p++; + if (!*script->script_p) return 0; + continue; + } + //comments /* */ + else if (*(script->script_p+1) == '*') + { + script->script_p++; + do + { + script->script_p++; + if (!*script->script_p) return 0; + if (*script->script_p == '\n') script->line++; + } + while(!(*script->script_p == '*' && *(script->script_p+1) == '/')); + script->script_p++; + if (!*script->script_p) return 0; + script->script_p++; + if (!*script->script_p) return 0; + continue; + } + } + break; + } + return 1; +} + +/* +=============== +Parse_ReadEscapeCharacter +=============== +*/ +static int Parse_ReadEscapeCharacter(script_t *script, char *ch) +{ + int c, val, i; + + //step over the leading '\\' + script->script_p++; + //determine the escape character + switch(*script->script_p) + { + case '\\': c = '\\'; break; + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 't': c = '\t'; break; + case 'v': c = '\v'; break; + case 'b': c = '\b'; break; + case 'f': c = '\f'; break; + case 'a': c = '\a'; break; + case '\'': c = '\''; break; + case '\"': c = '\"'; break; + case '\?': c = '\?'; break; + case 'x': + { + script->script_p++; + for (i = 0, val = 0; ; i++, script->script_p++) + { + c = *script->script_p; + if (c >= '0' && c <= '9') c = c - '0'; + else if (c >= 'A' && c <= 'Z') c = c - 'A' + 10; + else if (c >= 'a' && c <= 'z') c = c - 'a' + 10; + else break; + val = (val << 4) + c; + } + script->script_p--; + if (val > 0xFF) + { + Parse_ScriptWarning(script, "too large value in escape character"); + val = 0xFF; + } + c = val; + break; + } + default: //NOTE: decimal ASCII code, NOT octal + { + if (*script->script_p < '0' || *script->script_p > '9') Parse_ScriptError(script, "unknown escape char"); + for (i = 0, val = 0; ; i++, script->script_p++) + { + c = *script->script_p; + if (c >= '0' && c <= '9') c = c - '0'; + else break; + val = val * 10 + c; + } + script->script_p--; + if (val > 0xFF) + { + Parse_ScriptWarning(script, "too large value in escape character"); + val = 0xFF; + } + c = val; + break; + } + } + //step over the escape character or the last digit of the number + script->script_p++; + //store the escape character + *ch = c; + //succesfully read escape character + return 1; +} + +/* +=============== +Parse_ReadString + +Reads C-like string. Escape characters are interpretted. +Quotes are included with the string. +Reads two strings with a white space between them as one string. +=============== +*/ +static int Parse_ReadString(script_t *script, token_t *token, int quote) +{ + int len, tmpline; + char *tmpscript_p; + + if (quote == '\"') token->type = TT_STRING; + else token->type = TT_LITERAL; + + len = 0; + //leading quote + token->string[len++] = *script->script_p++; + // + while(1) + { + //minus 2 because trailing double quote and zero have to be appended + if (len >= MAX_TOKEN_CHARS - 2) + { + Parse_ScriptError(script, "string longer than MAX_TOKEN_CHARS = %d", MAX_TOKEN_CHARS); + return 0; + } + //if there is an escape character and + //if escape characters inside a string are allowed + if (*script->script_p == '\\' && !(script->flags & SCFL_NOSTRINGESCAPECHARS)) + { + if (!Parse_ReadEscapeCharacter(script, &token->string[len])) + { + token->string[len] = 0; + return 0; + } + len++; + } + //if a trailing quote + else if (*script->script_p == quote) + { + //step over the double quote + script->script_p++; + //if white spaces in a string are not allowed + if (script->flags & SCFL_NOSTRINGWHITESPACES) break; + // + tmpscript_p = script->script_p; + tmpline = script->line; + //read unusefull stuff between possible two following strings + if (!Parse_ReadWhiteSpace(script)) + { + script->script_p = tmpscript_p; + script->line = tmpline; + break; + } + //if there's no leading double qoute + if (*script->script_p != quote) + { + script->script_p = tmpscript_p; + script->line = tmpline; + break; + } + //step over the new leading double quote + script->script_p++; + } + else + { + if (*script->script_p == '\0') + { + token->string[len] = 0; + Parse_ScriptError(script, "missing trailing quote"); + return 0; + } + if (*script->script_p == '\n') + { + token->string[len] = 0; + Parse_ScriptError(script, "newline inside string %s", token->string); + return 0; + } + token->string[len++] = *script->script_p++; + } + } + //trailing quote + token->string[len++] = quote; + //end string with a zero + token->string[len] = '\0'; + //the sub type is the length of the string + token->subtype = len; + return 1; +} + +/* +=============== +Parse_ReadName +=============== +*/ +static int Parse_ReadName(script_t *script, token_t *token) +{ + int len = 0; + char c; + + token->type = TT_NAME; + do + { + token->string[len++] = *script->script_p++; + if (len >= MAX_TOKEN_CHARS) + { + Parse_ScriptError(script, "name longer than MAX_TOKEN_CHARS = %d", MAX_TOKEN_CHARS); + return 0; + } + c = *script->script_p; + } while ((c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || + c == '_'); + token->string[len] = '\0'; + //the sub type is the length of the name + token->subtype = len; + return 1; +} + +/* +=============== +Parse_NumberValue +=============== +*/ +static void Parse_NumberValue(char *string, int subtype, unsigned long int *intvalue, + double *floatvalue) +{ + unsigned long int dotfound = 0; + + *intvalue = 0; + *floatvalue = 0; + //floating point number + if (subtype & TT_FLOAT) + { + while(*string) + { + if (*string == '.') + { + if (dotfound) return; + dotfound = 10; + string++; + } + if (dotfound) + { + *floatvalue = *floatvalue + (double) (*string - '0') / + (double) dotfound; + dotfound *= 10; + } + else + { + *floatvalue = *floatvalue * 10.0 + (double) (*string - '0'); + } + string++; + } + *intvalue = (unsigned long) *floatvalue; + } + else if (subtype & TT_DECIMAL) + { + while(*string) *intvalue = *intvalue * 10 + (*string++ - '0'); + *floatvalue = *intvalue; + } + else if (subtype & TT_HEX) + { + //step over the leading 0x or 0X + string += 2; + while(*string) + { + *intvalue <<= 4; + if (*string >= 'a' && *string <= 'f') *intvalue += *string - 'a' + 10; + else if (*string >= 'A' && *string <= 'F') *intvalue += *string - 'A' + 10; + else *intvalue += *string - '0'; + string++; + } + *floatvalue = *intvalue; + } + else if (subtype & TT_OCTAL) + { + //step over the first zero + string += 1; + while(*string) *intvalue = (*intvalue << 3) + (*string++ - '0'); + *floatvalue = *intvalue; + } + else if (subtype & TT_BINARY) + { + //step over the leading 0b or 0B + string += 2; + while(*string) *intvalue = (*intvalue << 1) + (*string++ - '0'); + *floatvalue = *intvalue; + } +} + +/* +=============== +Parse_ReadNumber +=============== +*/ +static int Parse_ReadNumber(script_t *script, token_t *token) +{ + int len = 0, i; + int octal, dot; + char c; +// unsigned long int intvalue = 0; +// double floatvalue = 0; + + token->type = TT_NUMBER; + //check for a hexadecimal number + if (*script->script_p == '0' && + (*(script->script_p + 1) == 'x' || + *(script->script_p + 1) == 'X')) + { + token->string[len++] = *script->script_p++; + token->string[len++] = *script->script_p++; + c = *script->script_p; + //hexadecimal + while((c >= '0' && c <= '9') || + (c >= 'a' && c <= 'f') || + (c >= 'A' && c <= 'A')) + { + token->string[len++] = *script->script_p++; + if (len >= MAX_TOKEN_CHARS) + { + Parse_ScriptError(script, "hexadecimal number longer than MAX_TOKEN_CHARS = %d", MAX_TOKEN_CHARS); + return 0; + } + c = *script->script_p; + } + token->subtype |= TT_HEX; + } +#ifdef BINARYNUMBERS + //check for a binary number + else if (*script->script_p == '0' && + (*(script->script_p + 1) == 'b' || + *(script->script_p + 1) == 'B')) + { + token->string[len++] = *script->script_p++; + token->string[len++] = *script->script_p++; + c = *script->script_p; + //binary + while(c == '0' || c == '1') + { + token->string[len++] = *script->script_p++; + if (len >= MAX_TOKEN_CHARS) + { + Parse_ScriptError(script, "binary number longer than MAX_TOKEN_CHARS = %d", MAX_TOKEN_CHARS); + return 0; + } + c = *script->script_p; + } + token->subtype |= TT_BINARY; + } +#endif //BINARYNUMBERS + else //decimal or octal integer or floating point number + { + octal = qfalse; + dot = qfalse; + if (*script->script_p == '0') octal = qtrue; + while(1) + { + c = *script->script_p; + if (c == '.') dot = qtrue; + else if (c == '8' || c == '9') octal = qfalse; + else if (c < '0' || c > '9') break; + token->string[len++] = *script->script_p++; + if (len >= MAX_TOKEN_CHARS - 1) + { + Parse_ScriptError(script, "number longer than MAX_TOKEN_CHARS = %d", MAX_TOKEN_CHARS); + return 0; + } + } + if (octal) token->subtype |= TT_OCTAL; + else token->subtype |= TT_DECIMAL; + if (dot) token->subtype |= TT_FLOAT; + } + for (i = 0; i < 2; i++) + { + c = *script->script_p; + //check for a LONG number + if ( (c == 'l' || c == 'L') // bk001204 - brackets + && !(token->subtype & TT_LONG)) + { + script->script_p++; + token->subtype |= TT_LONG; + } + //check for an UNSIGNED number + else if ( (c == 'u' || c == 'U') // bk001204 - brackets + && !(token->subtype & (TT_UNSIGNED | TT_FLOAT))) + { + script->script_p++; + token->subtype |= TT_UNSIGNED; + } + } + token->string[len] = '\0'; + Parse_NumberValue(token->string, token->subtype, &token->intvalue, &token->floatvalue); + if (!(token->subtype & TT_FLOAT)) token->subtype |= TT_INTEGER; + return 1; +} + +/* +=============== +Parse_ReadPunctuation +=============== +*/ +static int Parse_ReadPunctuation(script_t *script, token_t *token) +{ + int len; + char *p; + punctuation_t *punc; + + for (punc = script->punctuationtable[(unsigned int)*script->script_p]; punc; punc = punc->next) + { + p = punc->p; + len = strlen(p); + //if the script contains at least as much characters as the punctuation + if (script->script_p + len <= script->end_p) + { + //if the script contains the punctuation + if (!strncmp(script->script_p, p, len)) + { + strncpy(token->string, p, MAX_TOKEN_CHARS); + script->script_p += len; + token->type = TT_PUNCTUATION; + //sub type is the number of the punctuation + token->subtype = punc->n; + return 1; + } + } + } + return 0; +} + +/* +=============== +Parse_ReadPrimitive +=============== +*/ +static int Parse_ReadPrimitive(script_t *script, token_t *token) +{ + int len; + + len = 0; + while(*script->script_p > ' ' && *script->script_p != ';') + { + if (len >= MAX_TOKEN_CHARS) + { + Parse_ScriptError(script, "primitive token longer than MAX_TOKEN_CHARS = %d", MAX_TOKEN_CHARS); + return 0; + } + token->string[len++] = *script->script_p++; + } + token->string[len] = 0; + //copy the token into the script structure + Com_Memcpy(&script->token, token, sizeof(token_t)); + //primitive reading successfull + return 1; +} + +/* +=============== +Parse_ReadSciptToken +=============== +*/ +static int Parse_ReadSciptToken(script_t *script, token_t *token) +{ + //if there is a token available (from UnreadToken) + if (script->tokenavailable) + { + script->tokenavailable = 0; + Com_Memcpy(token, &script->token, sizeof(token_t)); + return 1; + } + //save script pointer + script->lastscript_p = script->script_p; + //save line counter + script->lastline = script->line; + //clear the token stuff + Com_Memset(token, 0, sizeof(token_t)); + //start of the white space + script->whitespace_p = script->script_p; + token->whitespace_p = script->script_p; + //read unusefull stuff + if (!Parse_ReadWhiteSpace(script)) return 0; + + script->endwhitespace_p = script->script_p; + token->endwhitespace_p = script->script_p; + //line the token is on + token->line = script->line; + //number of lines crossed before token + token->linescrossed = script->line - script->lastline; + //if there is a leading double quote + if (*script->script_p == '\"') + { + if (!Parse_ReadString(script, token, '\"')) return 0; + } + //if an literal + else if (*script->script_p == '\'') + { + //if (!Parse_ReadLiteral(script, token)) return 0; + if (!Parse_ReadString(script, token, '\'')) return 0; + } + //if there is a number + else if ((*script->script_p >= '0' && *script->script_p <= '9') || + (*script->script_p == '.' && + (*(script->script_p + 1) >= '0' && *(script->script_p + 1) <= '9'))) + { + if (!Parse_ReadNumber(script, token)) return 0; + } + //if this is a primitive script + else if (script->flags & SCFL_PRIMITIVE) + { + return Parse_ReadPrimitive(script, token); + } + //if there is a name + else if ((*script->script_p >= 'a' && *script->script_p <= 'z') || + (*script->script_p >= 'A' && *script->script_p <= 'Z') || + *script->script_p == '_') + { + if (!Parse_ReadName(script, token)) return 0; + } + //check for punctuations + else if (!Parse_ReadPunctuation(script, token)) + { + Parse_ScriptError(script, "can't read token"); + return 0; + } + //copy the token into the script structure + Com_Memcpy(&script->token, token, sizeof(token_t)); + //succesfully read a token + return 1; +} + +/* +=============== +Parse_StripDoubleQuotes +=============== +*/ +static void Parse_StripDoubleQuotes(char *string) +{ + if (*string == '\"') + { + strcpy(string, string+1); + } + if (string[strlen(string)-1] == '\"') + { + string[strlen(string)-1] = '\0'; + } +} + +/* +=============== +Parse_EndOfScript +=============== +*/ +static int Parse_EndOfScript(script_t *script) +{ + return script->script_p >= script->end_p; +} + +/* +=============== +Parse_LoadScriptFile +=============== +*/ +static script_t *Parse_LoadScriptFile(const char *filename) +{ + fileHandle_t fp; + char pathname[MAX_QPATH]; + int length; + void *buffer; + script_t *script; + + if (strlen(basefolder)) + Com_sprintf(pathname, sizeof(pathname), "%s/%s", basefolder, filename); + else + Com_sprintf(pathname, sizeof(pathname), "%s", filename); + length = FS_FOpenFileRead( pathname, &fp, qfalse ); + if (!fp) return NULL; + + buffer = Z_Malloc(sizeof(script_t) + length + 1); + Com_Memset( buffer, 0, sizeof(script_t) + length + 1 ); + + script = (script_t *) buffer; + Com_Memset(script, 0, sizeof(script_t)); + strcpy(script->filename, filename); + script->buffer = (char *) buffer + sizeof(script_t); + script->buffer[length] = 0; + script->length = length; + //pointer in script buffer + script->script_p = script->buffer; + //pointer in script buffer before reading token + script->lastscript_p = script->buffer; + //pointer to end of script buffer + script->end_p = &script->buffer[length]; + //set if there's a token available in script->token + script->tokenavailable = 0; + // + script->line = 1; + script->lastline = 1; + // + Parse_SetScriptPunctuations(script, NULL); + // + FS_Read(script->buffer, length, fp); + FS_FCloseFile(fp); + // + script->length = COM_Compress(script->buffer); + + return script; +} + +/* +=============== +Parse_LoadScriptMemory +=============== +*/ +static script_t *Parse_LoadScriptMemory(char *ptr, int length, char *name) +{ + void *buffer; + script_t *script; + + buffer = Z_Malloc(sizeof(script_t) + length + 1); + Com_Memset( buffer, 0, sizeof(script_t) + length + 1 ); + + script = (script_t *) buffer; + Com_Memset(script, 0, sizeof(script_t)); + strcpy(script->filename, name); + script->buffer = (char *) buffer + sizeof(script_t); + script->buffer[length] = 0; + script->length = length; + //pointer in script buffer + script->script_p = script->buffer; + //pointer in script buffer before reading token + script->lastscript_p = script->buffer; + //pointer to end of script buffer + script->end_p = &script->buffer[length]; + //set if there's a token available in script->token + script->tokenavailable = 0; + // + script->line = 1; + script->lastline = 1; + // + Parse_SetScriptPunctuations(script, NULL); + // + Com_Memcpy(script->buffer, ptr, length); + // + return script; +} + +/* +=============== +Parse_FreeScript +=============== +*/ +static void Parse_FreeScript(script_t *script) +{ + if (script->punctuationtable) Z_Free(script->punctuationtable); + Z_Free(script); +} + +/* +=============== +Parse_SetBaseFolder +=============== +*/ +static void Parse_SetBaseFolder(char *path) +{ + Com_sprintf(basefolder, sizeof(basefolder), path); +} + +/* +=============== +Parse_SourceError +=============== +*/ +static void QDECL Parse_SourceError(source_t *source, char *str, ...) +{ + char text[1024]; + va_list ap; + + va_start(ap, str); + vsprintf(text, str, ap); + va_end(ap); + Com_Printf( "file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text); +} + +/* +=============== +Parse_SourceWarning +=============== +*/ +static void QDECL Parse_SourceWarning(source_t *source, char *str, ...) +{ + char text[1024]; + va_list ap; + + va_start(ap, str); + vsprintf(text, str, ap); + va_end(ap); + Com_Printf( "file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text); +} + +/* +=============== +Parse_PushIndent +=============== +*/ +static void Parse_PushIndent(source_t *source, int type, int skip) +{ + indent_t *indent; + + indent = (indent_t *) Z_Malloc(sizeof(indent_t)); + indent->type = type; + indent->script = source->scriptstack; + indent->skip = (skip != 0); + source->skip += indent->skip; + indent->next = source->indentstack; + source->indentstack = indent; +} + +/* +=============== +Parse_PopIndent +=============== +*/ +static void Parse_PopIndent(source_t *source, int *type, int *skip) +{ + indent_t *indent; + + *type = 0; + *skip = 0; + + indent = source->indentstack; + if (!indent) return; + + //must be an indent from the current script + if (source->indentstack->script != source->scriptstack) return; + + *type = indent->type; + *skip = indent->skip; + source->indentstack = source->indentstack->next; + source->skip -= indent->skip; + Z_Free(indent); +} + +/* +=============== +Parse_PushScript +=============== +*/ +static void Parse_PushScript(source_t *source, script_t *script) +{ + script_t *s; + + for (s = source->scriptstack; s; s = s->next) + { + if (!Q_stricmp(s->filename, script->filename)) + { + Parse_SourceError(source, "%s recursively included", script->filename); + return; + } + } + //push the script on the script stack + script->next = source->scriptstack; + source->scriptstack = script; +} + +/* +=============== +Parse_CopyToken +=============== +*/ +static token_t *Parse_CopyToken(token_t *token) +{ + token_t *t; + +// t = (token_t *) malloc(sizeof(token_t)); + t = (token_t *) Z_Malloc(sizeof(token_t)); +// t = freetokens; + if (!t) + { + Com_Error(ERR_FATAL, "out of token space\n"); + return NULL; + } +// freetokens = freetokens->next; + Com_Memcpy(t, token, sizeof(token_t)); + t->next = NULL; + numtokens++; + return t; +} + +/* +=============== +Parse_FreeToken +=============== +*/ +static void Parse_FreeToken(token_t *token) +{ + //free(token); + Z_Free(token); +// token->next = freetokens; +// freetokens = token; + numtokens--; +} + +/* +=============== +Parse_ReadSourceToken +=============== +*/ +static int Parse_ReadSourceToken(source_t *source, token_t *token) +{ + token_t *t; + script_t *script; + int type, skip; + + //if there's no token already available + while(!source->tokens) + { + //if there's a token to read from the script + if (Parse_ReadSciptToken(source->scriptstack, token)) return qtrue; + //if at the end of the script + if (Parse_EndOfScript(source->scriptstack)) + { + //remove all indents of the script + while(source->indentstack && + source->indentstack->script == source->scriptstack) + { + Parse_SourceWarning(source, "missing #endif"); + Parse_PopIndent(source, &type, &skip); + } + } + //if this was the initial script + if (!source->scriptstack->next) return qfalse; + //remove the script and return to the last one + script = source->scriptstack; + source->scriptstack = source->scriptstack->next; + Parse_FreeScript(script); + } + //copy the already available token + Com_Memcpy(token, source->tokens, sizeof(token_t)); + //free the read token + t = source->tokens; + source->tokens = source->tokens->next; + Parse_FreeToken(t); + return qtrue; +} + +/* +=============== +Parse_UnreadSourceToken +=============== +*/ +static int Parse_UnreadSourceToken(source_t *source, token_t *token) +{ + token_t *t; + + t = Parse_CopyToken(token); + t->next = source->tokens; + source->tokens = t; + return qtrue; +} + +/* +=============== +Parse_ReadDefineParms +=============== +*/ +static int Parse_ReadDefineParms(source_t *source, define_t *define, token_t **parms, int maxparms) +{ + token_t token, *t, *last; + int i, done, lastcomma, numparms, indent; + + if (!Parse_ReadSourceToken(source, &token)) + { + Parse_SourceError(source, "define %s missing parms", define->name); + return qfalse; + } + // + if (define->numparms > maxparms) + { + Parse_SourceError(source, "define with more than %d parameters", maxparms); + return qfalse; + } + // + for (i = 0; i < define->numparms; i++) parms[i] = NULL; + //if no leading "(" + if (strcmp(token.string, "(")) + { + Parse_UnreadSourceToken(source, &token); + Parse_SourceError(source, "define %s missing parms", define->name); + return qfalse; + } + //read the define parameters + for (done = 0, numparms = 0, indent = 0; !done;) + { + if (numparms >= maxparms) + { + Parse_SourceError(source, "define %s with too many parms", define->name); + return qfalse; + } + if (numparms >= define->numparms) + { + Parse_SourceWarning(source, "define %s has too many parms", define->name); + return qfalse; + } + parms[numparms] = NULL; + lastcomma = 1; + last = NULL; + while(!done) + { + // + if (!Parse_ReadSourceToken(source, &token)) + { + Parse_SourceError(source, "define %s incomplete", define->name); + return qfalse; + } + // + if (!strcmp(token.string, ",")) + { + if (indent <= 0) + { + if (lastcomma) Parse_SourceWarning(source, "too many comma's"); + lastcomma = 1; + break; + } + } + lastcomma = 0; + // + if (!strcmp(token.string, "(")) + { + indent++; + continue; + } + else if (!strcmp(token.string, ")")) + { + if (--indent <= 0) + { + if (!parms[define->numparms-1]) + { + Parse_SourceWarning(source, "too few define parms"); + } + done = 1; + break; + } + } + // + if (numparms < define->numparms) + { + // + t = Parse_CopyToken(&token); + t->next = NULL; + if (last) last->next = t; + else parms[numparms] = t; + last = t; + } + } + numparms++; + } + return qtrue; +} + +/* +=============== +Parse_StringizeTokens +=============== +*/ +static int Parse_StringizeTokens(token_t *tokens, token_t *token) +{ + token_t *t; + + token->type = TT_STRING; + token->whitespace_p = NULL; + token->endwhitespace_p = NULL; + token->string[0] = '\0'; + strcat(token->string, "\""); + for (t = tokens; t; t = t->next) + { + strncat(token->string, t->string, MAX_TOKEN_CHARS - strlen(token->string)); + } + strncat(token->string, "\"", MAX_TOKEN_CHARS - strlen(token->string)); + return qtrue; +} + +/* +=============== +Parse_MergeTokens +=============== +*/ +static int Parse_MergeTokens(token_t *t1, token_t *t2) +{ + //merging of a name with a name or number + if (t1->type == TT_NAME && (t2->type == TT_NAME || t2->type == TT_NUMBER)) + { + strcat(t1->string, t2->string); + return qtrue; + } + //merging of two strings + if (t1->type == TT_STRING && t2->type == TT_STRING) + { + //remove trailing double quote + t1->string[strlen(t1->string)-1] = '\0'; + //concat without leading double quote + strcat(t1->string, &t2->string[1]); + return qtrue; + } + //FIXME: merging of two number of the same sub type + return qfalse; +} + +/* +=============== +Parse_NameHash +=============== +*/ +//char primes[16] = {1, 3, 5, 7, 11, 13, 17, 19, 23, 27, 29, 31, 37, 41, 43, 47}; +static int Parse_NameHash(char *name) +{ + int register hash, i; + + hash = 0; + for (i = 0; name[i] != '\0'; i++) + { + hash += name[i] * (119 + i); + //hash += (name[i] << 7) + i; + //hash += (name[i] << (i&15)); + } + hash = (hash ^ (hash >> 10) ^ (hash >> 20)) & (DEFINEHASHSIZE-1); + return hash; +} + +/* +=============== +Parse_AddDefineToHash +=============== +*/ +static void Parse_AddDefineToHash(define_t *define, define_t **definehash) +{ + int hash; + + hash = Parse_NameHash(define->name); + define->hashnext = definehash[hash]; + definehash[hash] = define; +} + +/* +=============== +Parse_FindHashedDefine +=============== +*/ +static define_t *Parse_FindHashedDefine(define_t **definehash, char *name) +{ + define_t *d; + int hash; + + hash = Parse_NameHash(name); + for (d = definehash[hash]; d; d = d->hashnext) + { + if (!strcmp(d->name, name)) return d; + } + return NULL; +} + +/* +=============== +Parse_FindDefineParm +=============== +*/ +static int Parse_FindDefineParm(define_t *define, char *name) +{ + token_t *p; + int i; + + i = 0; + for (p = define->parms; p; p = p->next) + { + if (!strcmp(p->string, name)) return i; + i++; + } + return -1; +} + +/* +=============== +Parse_FreeDefine +=============== +*/ +static void Parse_FreeDefine(define_t *define) +{ + token_t *t, *next; + + //free the define parameters + for (t = define->parms; t; t = next) + { + next = t->next; + Parse_FreeToken(t); + } + //free the define tokens + for (t = define->tokens; t; t = next) + { + next = t->next; + Parse_FreeToken(t); + } + //free the define + Z_Free(define); +} + +/* +=============== +Parse_ExpandBuiltinDefine +=============== +*/ +static int Parse_ExpandBuiltinDefine(source_t *source, token_t *deftoken, define_t *define, + token_t **firsttoken, token_t **lasttoken) +{ + token_t *token; +#ifdef _WIN32 + unsigned long t; // time_t t; //to prevent LCC warning +#else + time_t t; +#endif + + char *curtime; + + token = Parse_CopyToken(deftoken); + switch(define->builtin) + { + case BUILTIN_LINE: + { + sprintf(token->string, "%d", deftoken->line); + token->intvalue = deftoken->line; + token->floatvalue = deftoken->line; + token->type = TT_NUMBER; + token->subtype = TT_DECIMAL | TT_INTEGER; + *firsttoken = token; + *lasttoken = token; + break; + } + case BUILTIN_FILE: + { + strcpy(token->string, source->scriptstack->filename); + token->type = TT_NAME; + token->subtype = strlen(token->string); + *firsttoken = token; + *lasttoken = token; + break; + } + case BUILTIN_DATE: + { + t = time(NULL); + curtime = ctime(&t); + strcpy(token->string, "\""); + strncat(token->string, curtime+4, 7); + strncat(token->string+7, curtime+20, 4); + strcat(token->string, "\""); + free(curtime); + token->type = TT_NAME; + token->subtype = strlen(token->string); + *firsttoken = token; + *lasttoken = token; + break; + } + case BUILTIN_TIME: + { + t = time(NULL); + curtime = ctime(&t); + strcpy(token->string, "\""); + strncat(token->string, curtime+11, 8); + strcat(token->string, "\""); + free(curtime); + token->type = TT_NAME; + token->subtype = strlen(token->string); + *firsttoken = token; + *lasttoken = token; + break; + } + case BUILTIN_STDC: + default: + { + *firsttoken = NULL; + *lasttoken = NULL; + break; + } + } + return qtrue; +} + +/* +=============== +Parse_ExpandDefine +=============== +*/ +static int Parse_ExpandDefine(source_t *source, token_t *deftoken, define_t *define, + token_t **firsttoken, token_t **lasttoken) +{ + token_t *parms[MAX_DEFINEPARMS], *dt, *pt, *t; + token_t *t1, *t2, *first, *last, *nextpt, token; + int parmnum, i; + + //if it is a builtin define + if (define->builtin) + { + return Parse_ExpandBuiltinDefine(source, deftoken, define, firsttoken, lasttoken); + } + //if the define has parameters + if (define->numparms) + { + if (!Parse_ReadDefineParms(source, define, parms, MAX_DEFINEPARMS)) return qfalse; + } + //empty list at first + first = NULL; + last = NULL; + //create a list with tokens of the expanded define + for (dt = define->tokens; dt; dt = dt->next) + { + parmnum = -1; + //if the token is a name, it could be a define parameter + if (dt->type == TT_NAME) + { + parmnum = Parse_FindDefineParm(define, dt->string); + } + //if it is a define parameter + if (parmnum >= 0) + { + for (pt = parms[parmnum]; pt; pt = pt->next) + { + t = Parse_CopyToken(pt); + //add the token to the list + t->next = NULL; + if (last) last->next = t; + else first = t; + last = t; + } + } + else + { + //if stringizing operator + if (dt->string[0] == '#' && dt->string[1] == '\0') + { + //the stringizing operator must be followed by a define parameter + if (dt->next) parmnum = Parse_FindDefineParm(define, dt->next->string); + else parmnum = -1; + // + if (parmnum >= 0) + { + //step over the stringizing operator + dt = dt->next; + //stringize the define parameter tokens + if (!Parse_StringizeTokens(parms[parmnum], &token)) + { + Parse_SourceError(source, "can't stringize tokens"); + return qfalse; + } + t = Parse_CopyToken(&token); + } + else + { + Parse_SourceWarning(source, "stringizing operator without define parameter"); + continue; + } + } + else + { + t = Parse_CopyToken(dt); + } + //add the token to the list + t->next = NULL; + if (last) last->next = t; + else first = t; + last = t; + } + } + //check for the merging operator + for (t = first; t; ) + { + if (t->next) + { + //if the merging operator + if (t->next->string[0] == '#' && t->next->string[1] == '#') + { + t1 = t; + t2 = t->next->next; + if (t2) + { + if (!Parse_MergeTokens(t1, t2)) + { + Parse_SourceError(source, "can't merge %s with %s", t1->string, t2->string); + return qfalse; + } + Parse_FreeToken(t1->next); + t1->next = t2->next; + if (t2 == last) last = t1; + Parse_FreeToken(t2); + continue; + } + } + } + t = t->next; + } + //store the first and last token of the list + *firsttoken = first; + *lasttoken = last; + //free all the parameter tokens + for (i = 0; i < define->numparms; i++) + { + for (pt = parms[i]; pt; pt = nextpt) + { + nextpt = pt->next; + Parse_FreeToken(pt); + } + } + // + return qtrue; +} + +/* +=============== +Parse_ExpandDefineIntoSource +=============== +*/ +static int Parse_ExpandDefineIntoSource(source_t *source, token_t *deftoken, define_t *define) +{ + token_t *firsttoken, *lasttoken; + + if (!Parse_ExpandDefine(source, deftoken, define, &firsttoken, &lasttoken)) return qfalse; + + if (firsttoken && lasttoken) + { + lasttoken->next = source->tokens; + source->tokens = firsttoken; + return qtrue; + } + return qfalse; +} + +/* +=============== +Parse_ConvertPath +=============== +*/ +static void Parse_ConvertPath(char *path) +{ + char *ptr; + + //remove double path seperators + for (ptr = path; *ptr;) + { + if ((*ptr == '\\' || *ptr == '/') && + (*(ptr+1) == '\\' || *(ptr+1) == '/')) + { + strcpy(ptr, ptr+1); + } + else + { + ptr++; + } + } + //set OS dependent path seperators + for (ptr = path; *ptr;) + { + if (*ptr == '/' || *ptr == '\\') *ptr = PATH_SEP; + ptr++; + } +} + +/* +=============== +Parse_ReadLine + +reads a token from the current line, continues reading on the next +line only if a backslash '\' is encountered. +=============== +*/ +static int Parse_ReadLine(source_t *source, token_t *token) +{ + int crossline; + + crossline = 0; + do + { + if (!Parse_ReadSourceToken(source, token)) return qfalse; + + if (token->linescrossed > crossline) + { + Parse_UnreadSourceToken(source, token); + return qfalse; + } + crossline = 1; + } while(!strcmp(token->string, "\\")); + return qtrue; +} + +/* +=============== +Parse_OperatorPriority +=============== +*/ +typedef struct operator_s +{ + int operator; + int priority; + int parentheses; + struct operator_s *prev, *next; +} operator_t; + +typedef struct value_s +{ + signed long int intvalue; + double floatvalue; + int parentheses; + struct value_s *prev, *next; +} value_t; + +static int Parse_OperatorPriority(int op) +{ + switch(op) + { + case P_MUL: return 15; + case P_DIV: return 15; + case P_MOD: return 15; + case P_ADD: return 14; + case P_SUB: return 14; + + case P_LOGIC_AND: return 7; + case P_LOGIC_OR: return 6; + case P_LOGIC_GEQ: return 12; + case P_LOGIC_LEQ: return 12; + case P_LOGIC_EQ: return 11; + case P_LOGIC_UNEQ: return 11; + + case P_LOGIC_NOT: return 16; + case P_LOGIC_GREATER: return 12; + case P_LOGIC_LESS: return 12; + + case P_RSHIFT: return 13; + case P_LSHIFT: return 13; + + case P_BIN_AND: return 10; + case P_BIN_OR: return 8; + case P_BIN_XOR: return 9; + case P_BIN_NOT: return 16; + + case P_COLON: return 5; + case P_QUESTIONMARK: return 5; + } + return qfalse; +} + +#define MAX_VALUES 64 +#define MAX_OPERATORS 64 +#define AllocValue(val) \ + if (numvalues >= MAX_VALUES) { \ + Parse_SourceError(source, "out of value space\n"); \ + error = 1; \ + break; \ + } \ + else \ + val = &value_heap[numvalues++]; +#define FreeValue(val) +// +#define AllocOperator(op) \ + if (numoperators >= MAX_OPERATORS) { \ + Parse_SourceError(source, "out of operator space\n"); \ + error = 1; \ + break; \ + } \ + else \ + op = &operator_heap[numoperators++]; +#define FreeOperator(op) + +/* +=============== +Parse_EvaluateTokens +=============== +*/ +static int Parse_EvaluateTokens(source_t *source, token_t *tokens, signed long int *intvalue, + double *floatvalue, int integer) +{ + operator_t *o, *firstoperator, *lastoperator; + value_t *v, *firstvalue, *lastvalue, *v1, *v2; + token_t *t; + int brace = 0; + int parentheses = 0; + int error = 0; + int lastwasvalue = 0; + int negativevalue = 0; + int questmarkintvalue = 0; + double questmarkfloatvalue = 0; + int gotquestmarkvalue = qfalse; + int lastoperatortype = 0; + // + operator_t operator_heap[MAX_OPERATORS]; + int numoperators = 0; + value_t value_heap[MAX_VALUES]; + int numvalues = 0; + + firstoperator = lastoperator = NULL; + firstvalue = lastvalue = NULL; + if (intvalue) *intvalue = 0; + if (floatvalue) *floatvalue = 0; + for (t = tokens; t; t = t->next) + { + switch(t->type) + { + case TT_NAME: + { + if (lastwasvalue || negativevalue) + { + Parse_SourceError(source, "syntax error in #if/#elif"); + error = 1; + break; + } + if (strcmp(t->string, "defined")) + { + Parse_SourceError(source, "undefined name %s in #if/#elif", t->string); + error = 1; + break; + } + t = t->next; + if (!strcmp(t->string, "(")) + { + brace = qtrue; + t = t->next; + } + if (!t || t->type != TT_NAME) + { + Parse_SourceError(source, "defined without name in #if/#elif"); + error = 1; + break; + } + //v = (value_t *) Z_Malloc(sizeof(value_t)); + AllocValue(v); + if (Parse_FindHashedDefine(source->definehash, t->string)) + { + v->intvalue = 1; + v->floatvalue = 1; + } + else + { + v->intvalue = 0; + v->floatvalue = 0; + } + v->parentheses = parentheses; + v->next = NULL; + v->prev = lastvalue; + if (lastvalue) lastvalue->next = v; + else firstvalue = v; + lastvalue = v; + if (brace) + { + t = t->next; + if (!t || strcmp(t->string, ")")) + { + Parse_SourceError(source, "defined without ) in #if/#elif"); + error = 1; + break; + } + } + brace = qfalse; + // defined() creates a value + lastwasvalue = 1; + break; + } + case TT_NUMBER: + { + if (lastwasvalue) + { + Parse_SourceError(source, "syntax error in #if/#elif"); + error = 1; + break; + } + //v = (value_t *) Z_Malloc(sizeof(value_t)); + AllocValue(v); + if (negativevalue) + { + v->intvalue = - (signed int) t->intvalue; + v->floatvalue = - t->floatvalue; + } + else + { + v->intvalue = t->intvalue; + v->floatvalue = t->floatvalue; + } + v->parentheses = parentheses; + v->next = NULL; + v->prev = lastvalue; + if (lastvalue) lastvalue->next = v; + else firstvalue = v; + lastvalue = v; + //last token was a value + lastwasvalue = 1; + // + negativevalue = 0; + break; + } + case TT_PUNCTUATION: + { + if (negativevalue) + { + Parse_SourceError(source, "misplaced minus sign in #if/#elif"); + error = 1; + break; + } + if (t->subtype == P_PARENTHESESOPEN) + { + parentheses++; + break; + } + else if (t->subtype == P_PARENTHESESCLOSE) + { + parentheses--; + if (parentheses < 0) + { + Parse_SourceError(source, "too many ) in #if/#elsif"); + error = 1; + } + break; + } + //check for invalid operators on floating point values + if (!integer) + { + if (t->subtype == P_BIN_NOT || t->subtype == P_MOD || + t->subtype == P_RSHIFT || t->subtype == P_LSHIFT || + t->subtype == P_BIN_AND || t->subtype == P_BIN_OR || + t->subtype == P_BIN_XOR) + { + Parse_SourceError(source, "illigal operator %s on floating point operands\n", t->string); + error = 1; + break; + } + } + switch(t->subtype) + { + case P_LOGIC_NOT: + case P_BIN_NOT: + { + if (lastwasvalue) + { + Parse_SourceError(source, "! or ~ after value in #if/#elif"); + error = 1; + break; + } + break; + } + case P_INC: + case P_DEC: + { + Parse_SourceError(source, "++ or -- used in #if/#elif"); + break; + } + case P_SUB: + { + if (!lastwasvalue) + { + negativevalue = 1; + break; + } + } + + case P_MUL: + case P_DIV: + case P_MOD: + case P_ADD: + + case P_LOGIC_AND: + case P_LOGIC_OR: + case P_LOGIC_GEQ: + case P_LOGIC_LEQ: + case P_LOGIC_EQ: + case P_LOGIC_UNEQ: + + case P_LOGIC_GREATER: + case P_LOGIC_LESS: + + case P_RSHIFT: + case P_LSHIFT: + + case P_BIN_AND: + case P_BIN_OR: + case P_BIN_XOR: + + case P_COLON: + case P_QUESTIONMARK: + { + if (!lastwasvalue) + { + Parse_SourceError(source, "operator %s after operator in #if/#elif", t->string); + error = 1; + break; + } + break; + } + default: + { + Parse_SourceError(source, "invalid operator %s in #if/#elif", t->string); + error = 1; + break; + } + } + if (!error && !negativevalue) + { + //o = (operator_t *) Z_Malloc(sizeof(operator_t)); + AllocOperator(o); + o->operator = t->subtype; + o->priority = Parse_OperatorPriority(t->subtype); + o->parentheses = parentheses; + o->next = NULL; + o->prev = lastoperator; + if (lastoperator) lastoperator->next = o; + else firstoperator = o; + lastoperator = o; + lastwasvalue = 0; + } + break; + } + default: + { + Parse_SourceError(source, "unknown %s in #if/#elif", t->string); + error = 1; + break; + } + } + if (error) break; + } + if (!error) + { + if (!lastwasvalue) + { + Parse_SourceError(source, "trailing operator in #if/#elif"); + error = 1; + } + else if (parentheses) + { + Parse_SourceError(source, "too many ( in #if/#elif"); + error = 1; + } + } + // + gotquestmarkvalue = qfalse; + questmarkintvalue = 0; + questmarkfloatvalue = 0; + //while there are operators + while(!error && firstoperator) + { + v = firstvalue; + for (o = firstoperator; o->next; o = o->next) + { + //if the current operator is nested deeper in parentheses + //than the next operator + if (o->parentheses > o->next->parentheses) break; + //if the current and next operator are nested equally deep in parentheses + if (o->parentheses == o->next->parentheses) + { + //if the priority of the current operator is equal or higher + //than the priority of the next operator + if (o->priority >= o->next->priority) break; + } + //if the arity of the operator isn't equal to 1 + if (o->operator != P_LOGIC_NOT + && o->operator != P_BIN_NOT) v = v->next; + //if there's no value or no next value + if (!v) + { + Parse_SourceError(source, "mising values in #if/#elif"); + error = 1; + break; + } + } + if (error) break; + v1 = v; + v2 = v->next; + switch(o->operator) + { + case P_LOGIC_NOT: v1->intvalue = !v1->intvalue; + v1->floatvalue = !v1->floatvalue; break; + case P_BIN_NOT: v1->intvalue = ~v1->intvalue; + break; + case P_MUL: v1->intvalue *= v2->intvalue; + v1->floatvalue *= v2->floatvalue; break; + case P_DIV: if (!v2->intvalue || !v2->floatvalue) + { + Parse_SourceError(source, "divide by zero in #if/#elif\n"); + error = 1; + break; + } + v1->intvalue /= v2->intvalue; + v1->floatvalue /= v2->floatvalue; break; + case P_MOD: if (!v2->intvalue) + { + Parse_SourceError(source, "divide by zero in #if/#elif\n"); + error = 1; + break; + } + v1->intvalue %= v2->intvalue; break; + case P_ADD: v1->intvalue += v2->intvalue; + v1->floatvalue += v2->floatvalue; break; + case P_SUB: v1->intvalue -= v2->intvalue; + v1->floatvalue -= v2->floatvalue; break; + case P_LOGIC_AND: v1->intvalue = v1->intvalue && v2->intvalue; + v1->floatvalue = v1->floatvalue && v2->floatvalue; break; + case P_LOGIC_OR: v1->intvalue = v1->intvalue || v2->intvalue; + v1->floatvalue = v1->floatvalue || v2->floatvalue; break; + case P_LOGIC_GEQ: v1->intvalue = v1->intvalue >= v2->intvalue; + v1->floatvalue = v1->floatvalue >= v2->floatvalue; break; + case P_LOGIC_LEQ: v1->intvalue = v1->intvalue <= v2->intvalue; + v1->floatvalue = v1->floatvalue <= v2->floatvalue; break; + case P_LOGIC_EQ: v1->intvalue = v1->intvalue == v2->intvalue; + v1->floatvalue = v1->floatvalue == v2->floatvalue; break; + case P_LOGIC_UNEQ: v1->intvalue = v1->intvalue != v2->intvalue; + v1->floatvalue = v1->floatvalue != v2->floatvalue; break; + case P_LOGIC_GREATER: v1->intvalue = v1->intvalue > v2->intvalue; + v1->floatvalue = v1->floatvalue > v2->floatvalue; break; + case P_LOGIC_LESS: v1->intvalue = v1->intvalue < v2->intvalue; + v1->floatvalue = v1->floatvalue < v2->floatvalue; break; + case P_RSHIFT: v1->intvalue >>= v2->intvalue; + break; + case P_LSHIFT: v1->intvalue <<= v2->intvalue; + break; + case P_BIN_AND: v1->intvalue &= v2->intvalue; + break; + case P_BIN_OR: v1->intvalue |= v2->intvalue; + break; + case P_BIN_XOR: v1->intvalue ^= v2->intvalue; + break; + case P_COLON: + { + if (!gotquestmarkvalue) + { + Parse_SourceError(source, ": without ? in #if/#elif"); + error = 1; + break; + } + if (integer) + { + if (!questmarkintvalue) v1->intvalue = v2->intvalue; + } + else + { + if (!questmarkfloatvalue) v1->floatvalue = v2->floatvalue; + } + gotquestmarkvalue = qfalse; + break; + } + case P_QUESTIONMARK: + { + if (gotquestmarkvalue) + { + Parse_SourceError(source, "? after ? in #if/#elif"); + error = 1; + break; + } + questmarkintvalue = v1->intvalue; + questmarkfloatvalue = v1->floatvalue; + gotquestmarkvalue = qtrue; + break; + } + } + if (error) break; + lastoperatortype = o->operator; + //if not an operator with arity 1 + if (o->operator != P_LOGIC_NOT + && o->operator != P_BIN_NOT) + { + //remove the second value if not question mark operator + if (o->operator != P_QUESTIONMARK) v = v->next; + // + if (v->prev) v->prev->next = v->next; + else firstvalue = v->next; + if (v->next) v->next->prev = v->prev; + else lastvalue = v->prev; + //Z_Free(v); + FreeValue(v); + } + //remove the operator + if (o->prev) o->prev->next = o->next; + else firstoperator = o->next; + if (o->next) o->next->prev = o->prev; + else lastoperator = o->prev; + //Z_Free(o); + FreeOperator(o); + } + if (firstvalue) + { + if (intvalue) *intvalue = firstvalue->intvalue; + if (floatvalue) *floatvalue = firstvalue->floatvalue; + } + for (o = firstoperator; o; o = lastoperator) + { + lastoperator = o->next; + //Z_Free(o); + FreeOperator(o); + } + for (v = firstvalue; v; v = lastvalue) + { + lastvalue = v->next; + //Z_Free(v); + FreeValue(v); + } + if (!error) return qtrue; + if (intvalue) *intvalue = 0; + if (floatvalue) *floatvalue = 0; + return qfalse; +} + +/* +=============== +Parse_Evaluate +=============== +*/ +static int Parse_Evaluate(source_t *source, signed long int *intvalue, + double *floatvalue, int integer) +{ + token_t token, *firsttoken, *lasttoken; + token_t *t, *nexttoken; + define_t *define; + int defined = qfalse; + + if (intvalue) *intvalue = 0; + if (floatvalue) *floatvalue = 0; + // + if (!Parse_ReadLine(source, &token)) + { + Parse_SourceError(source, "no value after #if/#elif"); + return qfalse; + } + firsttoken = NULL; + lasttoken = NULL; + do + { + //if the token is a name + if (token.type == TT_NAME) + { + if (defined) + { + defined = qfalse; + t = Parse_CopyToken(&token); + t->next = NULL; + if (lasttoken) lasttoken->next = t; + else firsttoken = t; + lasttoken = t; + } + else if (!strcmp(token.string, "defined")) + { + defined = qtrue; + t = Parse_CopyToken(&token); + t->next = NULL; + if (lasttoken) lasttoken->next = t; + else firsttoken = t; + lasttoken = t; + } + else + { + //then it must be a define + define = Parse_FindHashedDefine(source->definehash, token.string); + if (!define) + { + Parse_SourceError(source, "can't evaluate %s, not defined", token.string); + return qfalse; + } + if (!Parse_ExpandDefineIntoSource(source, &token, define)) return qfalse; + } + } + //if the token is a number or a punctuation + else if (token.type == TT_NUMBER || token.type == TT_PUNCTUATION) + { + t = Parse_CopyToken(&token); + t->next = NULL; + if (lasttoken) lasttoken->next = t; + else firsttoken = t; + lasttoken = t; + } + else //can't evaluate the token + { + Parse_SourceError(source, "can't evaluate %s", token.string); + return qfalse; + } + } while(Parse_ReadLine(source, &token)); + // + if (!Parse_EvaluateTokens(source, firsttoken, intvalue, floatvalue, integer)) return qfalse; + // + for (t = firsttoken; t; t = nexttoken) + { + nexttoken = t->next; + Parse_FreeToken(t); + } + // + return qtrue; +} + +/* +=============== +Parse_DollarEvaluate +=============== +*/ +static int Parse_DollarEvaluate(source_t *source, signed long int *intvalue, + double *floatvalue, int integer) +{ + int indent, defined = qfalse; + token_t token, *firsttoken, *lasttoken; + token_t *t, *nexttoken; + define_t *define; + + if (intvalue) *intvalue = 0; + if (floatvalue) *floatvalue = 0; + // + if (!Parse_ReadSourceToken(source, &token)) + { + Parse_SourceError(source, "no leading ( after $evalint/$evalfloat"); + return qfalse; + } + if (!Parse_ReadSourceToken(source, &token)) + { + Parse_SourceError(source, "nothing to evaluate"); + return qfalse; + } + indent = 1; + firsttoken = NULL; + lasttoken = NULL; + do + { + //if the token is a name + if (token.type == TT_NAME) + { + if (defined) + { + defined = qfalse; + t = Parse_CopyToken(&token); + t->next = NULL; + if (lasttoken) lasttoken->next = t; + else firsttoken = t; + lasttoken = t; + } + else if (!strcmp(token.string, "defined")) + { + defined = qtrue; + t = Parse_CopyToken(&token); + t->next = NULL; + if (lasttoken) lasttoken->next = t; + else firsttoken = t; + lasttoken = t; + } + else + { + //then it must be a define + define = Parse_FindHashedDefine(source->definehash, token.string); + if (!define) + { + Parse_SourceError(source, "can't evaluate %s, not defined", token.string); + return qfalse; + } + if (!Parse_ExpandDefineIntoSource(source, &token, define)) return qfalse; + } + } + //if the token is a number or a punctuation + else if (token.type == TT_NUMBER || token.type == TT_PUNCTUATION) + { + if (*token.string == '(') indent++; + else if (*token.string == ')') indent--; + if (indent <= 0) break; + t = Parse_CopyToken(&token); + t->next = NULL; + if (lasttoken) lasttoken->next = t; + else firsttoken = t; + lasttoken = t; + } + else //can't evaluate the token + { + Parse_SourceError(source, "can't evaluate %s", token.string); + return qfalse; + } + } while(Parse_ReadSourceToken(source, &token)); + // + if (!Parse_EvaluateTokens(source, firsttoken, intvalue, floatvalue, integer)) return qfalse; + // + for (t = firsttoken; t; t = nexttoken) + { + nexttoken = t->next; + Parse_FreeToken(t); + } + // + return qtrue; +} + +/* +=============== +Parse_Directive_include +=============== +*/ +static int Parse_Directive_include(source_t *source) +{ + script_t *script; + token_t token; + char path[MAX_QPATH]; + + if (source->skip > 0) return qtrue; + // + if (!Parse_ReadSourceToken(source, &token)) + { + Parse_SourceError(source, "#include without file name"); + return qfalse; + } + if (token.linescrossed > 0) + { + Parse_SourceError(source, "#include without file name"); + return qfalse; + } + if (token.type == TT_STRING) + { + Parse_StripDoubleQuotes(token.string); + Parse_ConvertPath(token.string); + script = Parse_LoadScriptFile(token.string); + if (!script) + { + strcpy(path, source->includepath); + strcat(path, token.string); + script = Parse_LoadScriptFile(path); + } + } + else if (token.type == TT_PUNCTUATION && *token.string == '<') + { + strcpy(path, source->includepath); + while(Parse_ReadSourceToken(source, &token)) + { + if (token.linescrossed > 0) + { + Parse_UnreadSourceToken(source, &token); + break; + } + if (token.type == TT_PUNCTUATION && *token.string == '>') break; + strncat(path, token.string, MAX_QPATH); + } + if (*token.string != '>') + { + Parse_SourceWarning(source, "#include missing trailing >"); + } + if (!strlen(path)) + { + Parse_SourceError(source, "#include without file name between < >"); + return qfalse; + } + Parse_ConvertPath(path); + script = Parse_LoadScriptFile(path); + } + else + { + Parse_SourceError(source, "#include without file name"); + return qfalse; + } + if (!script) + { + Parse_SourceError(source, "file %s not found", path); + return qfalse; + } + Parse_PushScript(source, script); + return qtrue; +} + +/* +=============== +Parse_WhiteSpaceBeforeToken +=============== +*/ +static int Parse_WhiteSpaceBeforeToken(token_t *token) +{ + return token->endwhitespace_p - token->whitespace_p > 0; +} + +/* +=============== +Parse_ClearTokenWhiteSpace +=============== +*/ +static void Parse_ClearTokenWhiteSpace(token_t *token) +{ + token->whitespace_p = NULL; + token->endwhitespace_p = NULL; + token->linescrossed = 0; +} + +/* +=============== +Parse_Directive_undef +=============== +*/ +static int Parse_Directive_undef(source_t *source) +{ + token_t token; + define_t *define, *lastdefine; + int hash; + + if (source->skip > 0) return qtrue; + // + if (!Parse_ReadLine(source, &token)) + { + Parse_SourceError(source, "undef without name"); + return qfalse; + } + if (token.type != TT_NAME) + { + Parse_UnreadSourceToken(source, &token); + Parse_SourceError(source, "expected name, found %s", token.string); + return qfalse; + } + + hash = Parse_NameHash(token.string); + for (lastdefine = NULL, define = source->definehash[hash]; define; define = define->hashnext) + { + if (!strcmp(define->name, token.string)) + { + if (define->flags & DEFINE_FIXED) + { + Parse_SourceWarning(source, "can't undef %s", token.string); + } + else + { + if (lastdefine) lastdefine->hashnext = define->hashnext; + else source->definehash[hash] = define->hashnext; + Parse_FreeDefine(define); + } + break; + } + lastdefine = define; + } + return qtrue; +} + +/* +=============== +Parse_Directive_elif +=============== +*/ +static int Parse_Directive_elif(source_t *source) +{ + signed long int value; + int type, skip; + + Parse_PopIndent(source, &type, &skip); + if (!type || type == INDENT_ELSE) + { + Parse_SourceError(source, "misplaced #elif"); + return qfalse; + } + if (!Parse_Evaluate(source, &value, NULL, qtrue)) return qfalse; + skip = (value == 0); + Parse_PushIndent(source, INDENT_ELIF, skip); + return qtrue; +} + +/* +=============== +Parse_Directive_if +=============== +*/ +static int Parse_Directive_if(source_t *source) +{ + signed long int value; + int skip; + + if (!Parse_Evaluate(source, &value, NULL, qtrue)) return qfalse; + skip = (value == 0); + Parse_PushIndent(source, INDENT_IF, skip); + return qtrue; +} + +/* +=============== +Parse_Directive_line +=============== +*/ +static int Parse_Directive_line(source_t *source) +{ + Parse_SourceError(source, "#line directive not supported"); + return qfalse; +} + +/* +=============== +Parse_Directive_error +=============== +*/ +static int Parse_Directive_error(source_t *source) +{ + token_t token; + + strcpy(token.string, ""); + Parse_ReadSourceToken(source, &token); + Parse_SourceError(source, "#error directive: %s", token.string); + return qfalse; +} + +/* +=============== +Parse_Directive_pragma +=============== +*/ +static int Parse_Directive_pragma(source_t *source) +{ + token_t token; + + Parse_SourceWarning(source, "#pragma directive not supported"); + while(Parse_ReadLine(source, &token)) ; + return qtrue; +} + +/* +=============== +Parse_UnreadSignToken +=============== +*/ +static void Parse_UnreadSignToken(source_t *source) +{ + token_t token; + + token.line = source->scriptstack->line; + token.whitespace_p = source->scriptstack->script_p; + token.endwhitespace_p = source->scriptstack->script_p; + token.linescrossed = 0; + strcpy(token.string, "-"); + token.type = TT_PUNCTUATION; + token.subtype = P_SUB; + Parse_UnreadSourceToken(source, &token); +} + +/* +=============== +Parse_Directive_eval +=============== +*/ +static int Parse_Directive_eval(source_t *source) +{ + signed long int value; + token_t token; + + if (!Parse_Evaluate(source, &value, NULL, qtrue)) return qfalse; + // + token.line = source->scriptstack->line; + token.whitespace_p = source->scriptstack->script_p; + token.endwhitespace_p = source->scriptstack->script_p; + token.linescrossed = 0; + sprintf(token.string, "%d", abs(value)); + token.type = TT_NUMBER; + token.subtype = TT_INTEGER|TT_LONG|TT_DECIMAL; + Parse_UnreadSourceToken(source, &token); + if (value < 0) Parse_UnreadSignToken(source); + return qtrue; +} + +/* +=============== +Parse_Directive_evalfloat +=============== +*/ +static int Parse_Directive_evalfloat(source_t *source) +{ + double value; + token_t token; + + if (!Parse_Evaluate(source, NULL, &value, qfalse)) return qfalse; + token.line = source->scriptstack->line; + token.whitespace_p = source->scriptstack->script_p; + token.endwhitespace_p = source->scriptstack->script_p; + token.linescrossed = 0; + sprintf(token.string, "%1.2f", fabs(value)); + token.type = TT_NUMBER; + token.subtype = TT_FLOAT|TT_LONG|TT_DECIMAL; + Parse_UnreadSourceToken(source, &token); + if (value < 0) Parse_UnreadSignToken(source); + return qtrue; +} + +/* +=============== +Parse_DollarDirective_evalint +=============== +*/ +static int Parse_DollarDirective_evalint(source_t *source) +{ + signed long int value; + token_t token; + + if (!Parse_DollarEvaluate(source, &value, NULL, qtrue)) return qfalse; + // + token.line = source->scriptstack->line; + token.whitespace_p = source->scriptstack->script_p; + token.endwhitespace_p = source->scriptstack->script_p; + token.linescrossed = 0; + sprintf(token.string, "%d", abs(value)); + token.type = TT_NUMBER; + token.subtype = TT_INTEGER|TT_LONG|TT_DECIMAL; + token.intvalue = value; + token.floatvalue = value; + Parse_UnreadSourceToken(source, &token); + if (value < 0) Parse_UnreadSignToken(source); + return qtrue; +} + +/* +=============== +Parse_DollarDirective_evalfloat +=============== +*/ +static int Parse_DollarDirective_evalfloat(source_t *source) +{ + double value; + token_t token; + + if (!Parse_DollarEvaluate(source, NULL, &value, qfalse)) return qfalse; + token.line = source->scriptstack->line; + token.whitespace_p = source->scriptstack->script_p; + token.endwhitespace_p = source->scriptstack->script_p; + token.linescrossed = 0; + sprintf(token.string, "%1.2f", fabs(value)); + token.type = TT_NUMBER; + token.subtype = TT_FLOAT|TT_LONG|TT_DECIMAL; + token.intvalue = (unsigned long) value; + token.floatvalue = value; + Parse_UnreadSourceToken(source, &token); + if (value < 0) Parse_UnreadSignToken(source); + return qtrue; +} + +/* +=============== +Parse_ReadDollarDirective +=============== +*/ +directive_t dollardirectives[20] = +{ + {"evalint", Parse_DollarDirective_evalint}, + {"evalfloat", Parse_DollarDirective_evalfloat}, + {NULL, NULL} +}; + +static int Parse_ReadDollarDirective(source_t *source) +{ + token_t token; + int i; + + //read the directive name + if (!Parse_ReadSourceToken(source, &token)) + { + Parse_SourceError(source, "found $ without name"); + return qfalse; + } + //directive name must be on the same line + if (token.linescrossed > 0) + { + Parse_UnreadSourceToken(source, &token); + Parse_SourceError(source, "found $ at end of line"); + return qfalse; + } + //if if is a name + if (token.type == TT_NAME) + { + //find the precompiler directive + for (i = 0; dollardirectives[i].name; i++) + { + if (!strcmp(dollardirectives[i].name, token.string)) + { + return dollardirectives[i].func(source); + } + } + } + Parse_UnreadSourceToken(source, &token); + Parse_SourceError(source, "unknown precompiler directive %s", token.string); + return qfalse; +} + +/* +=============== +Parse_Directive_if_def +=============== +*/ +static int Parse_Directive_if_def(source_t *source, int type) +{ + token_t token; + define_t *d; + int skip; + + if (!Parse_ReadLine(source, &token)) + { + Parse_SourceError(source, "#ifdef without name"); + return qfalse; + } + if (token.type != TT_NAME) + { + Parse_UnreadSourceToken(source, &token); + Parse_SourceError(source, "expected name after #ifdef, found %s", token.string); + return qfalse; + } + d = Parse_FindHashedDefine(source->definehash, token.string); + skip = (type == INDENT_IFDEF) == (d == NULL); + Parse_PushIndent(source, type, skip); + return qtrue; +} + +/* +=============== +Parse_Directive_ifdef +=============== +*/ +static int Parse_Directive_ifdef(source_t *source) +{ + return Parse_Directive_if_def(source, INDENT_IFDEF); +} + +/* +=============== +Parse_Directive_ifndef +=============== +*/ +static int Parse_Directive_ifndef(source_t *source) +{ + return Parse_Directive_if_def(source, INDENT_IFNDEF); +} + +/* +=============== +Parse_Directive_else +=============== +*/ +static int Parse_Directive_else(source_t *source) +{ + int type, skip; + + Parse_PopIndent(source, &type, &skip); + if (!type) + { + Parse_SourceError(source, "misplaced #else"); + return qfalse; + } + if (type == INDENT_ELSE) + { + Parse_SourceError(source, "#else after #else"); + return qfalse; + } + Parse_PushIndent(source, INDENT_ELSE, !skip); + return qtrue; +} + +/* +=============== +Parse_Directive_endif +=============== +*/ +static int Parse_Directive_endif(source_t *source) +{ + int type, skip; + + Parse_PopIndent(source, &type, &skip); + if (!type) + { + Parse_SourceError(source, "misplaced #endif"); + return qfalse; + } + return qtrue; +} + +/* +=============== +Parse_CheckTokenString +=============== +*/ +static int Parse_CheckTokenString(source_t *source, char *string) +{ + token_t tok; + + if (!Parse_ReadToken(source, &tok)) return qfalse; + //if the token is available + if (!strcmp(tok.string, string)) return qtrue; + // + Parse_UnreadSourceToken(source, &tok); + return qfalse; +} + +/* +=============== +Parse_Directive_define +=============== +*/ +static int Parse_Directive_define(source_t *source) +{ + token_t token, *t, *last; + define_t *define; + + if (source->skip > 0) return qtrue; + // + if (!Parse_ReadLine(source, &token)) + { + Parse_SourceError(source, "#define without name"); + return qfalse; + } + if (token.type != TT_NAME) + { + Parse_UnreadSourceToken(source, &token); + Parse_SourceError(source, "expected name after #define, found %s", token.string); + return qfalse; + } + //check if the define already exists + define = Parse_FindHashedDefine(source->definehash, token.string); + if (define) + { + if (define->flags & DEFINE_FIXED) + { + Parse_SourceError(source, "can't redefine %s", token.string); + return qfalse; + } + Parse_SourceWarning(source, "redefinition of %s", token.string); + //unread the define name before executing the #undef directive + Parse_UnreadSourceToken(source, &token); + if (!Parse_Directive_undef(source)) return qfalse; + //if the define was not removed (define->flags & DEFINE_FIXED) + define = Parse_FindHashedDefine(source->definehash, token.string); + } + //allocate define + define = (define_t *) Z_Malloc(sizeof(define_t) + strlen(token.string) + 1); + Com_Memset(define, 0, sizeof(define_t)); + define->name = (char *) define + sizeof(define_t); + strcpy(define->name, token.string); + //add the define to the source + Parse_AddDefineToHash(define, source->definehash); + //if nothing is defined, just return + if (!Parse_ReadLine(source, &token)) return qtrue; + //if it is a define with parameters + if (!Parse_WhiteSpaceBeforeToken(&token) && !strcmp(token.string, "(")) + { + //read the define parameters + last = NULL; + if (!Parse_CheckTokenString(source, ")")) + { + while(1) + { + if (!Parse_ReadLine(source, &token)) + { + Parse_SourceError(source, "expected define parameter"); + return qfalse; + } + //if it isn't a name + if (token.type != TT_NAME) + { + Parse_SourceError(source, "invalid define parameter"); + return qfalse; + } + // + if (Parse_FindDefineParm(define, token.string) >= 0) + { + Parse_SourceError(source, "two the same define parameters"); + return qfalse; + } + //add the define parm + t = Parse_CopyToken(&token); + Parse_ClearTokenWhiteSpace(t); + t->next = NULL; + if (last) last->next = t; + else define->parms = t; + last = t; + define->numparms++; + //read next token + if (!Parse_ReadLine(source, &token)) + { + Parse_SourceError(source, "define parameters not terminated"); + return qfalse; + } + // + if (!strcmp(token.string, ")")) break; + //then it must be a comma + if (strcmp(token.string, ",")) + { + Parse_SourceError(source, "define not terminated"); + return qfalse; + } + } + } + if (!Parse_ReadLine(source, &token)) return qtrue; + } + //read the defined stuff + last = NULL; + do + { + t = Parse_CopyToken(&token); + if (t->type == TT_NAME && !strcmp(t->string, define->name)) + { + Parse_SourceError(source, "recursive define (removed recursion)"); + continue; + } + Parse_ClearTokenWhiteSpace(t); + t->next = NULL; + if (last) last->next = t; + else define->tokens = t; + last = t; + } while(Parse_ReadLine(source, &token)); + // + if (last) + { + //check for merge operators at the beginning or end + if (!strcmp(define->tokens->string, "##") || + !strcmp(last->string, "##")) + { + Parse_SourceError(source, "define with misplaced ##"); + return qfalse; + } + } + return qtrue; +} + +/* +=============== +Parse_ReadDirective +=============== +*/ +directive_t directives[20] = +{ + {"if", Parse_Directive_if}, + {"ifdef", Parse_Directive_ifdef}, + {"ifndef", Parse_Directive_ifndef}, + {"elif", Parse_Directive_elif}, + {"else", Parse_Directive_else}, + {"endif", Parse_Directive_endif}, + {"include", Parse_Directive_include}, + {"define", Parse_Directive_define}, + {"undef", Parse_Directive_undef}, + {"line", Parse_Directive_line}, + {"error", Parse_Directive_error}, + {"pragma", Parse_Directive_pragma}, + {"eval", Parse_Directive_eval}, + {"evalfloat", Parse_Directive_evalfloat}, + {NULL, NULL} +}; + +static int Parse_ReadDirective(source_t *source) +{ + token_t token; + int i; + + //read the directive name + if (!Parse_ReadSourceToken(source, &token)) + { + Parse_SourceError(source, "found # without name"); + return qfalse; + } + //directive name must be on the same line + if (token.linescrossed > 0) + { + Parse_UnreadSourceToken(source, &token); + Parse_SourceError(source, "found # at end of line"); + return qfalse; + } + //if if is a name + if (token.type == TT_NAME) + { + //find the precompiler directive + for (i = 0; directives[i].name; i++) + { + if (!strcmp(directives[i].name, token.string)) + { + return directives[i].func(source); + } + } + } + Parse_SourceError(source, "unknown precompiler directive %s", token.string); + return qfalse; +} + +/* +=============== +Parse_UnreadToken +=============== +*/ +static void Parse_UnreadToken(source_t *source, token_t *token) +{ + Parse_UnreadSourceToken(source, token); +} + +/* +=============== +Parse_ReadToken +=============== +*/ +static int Parse_ReadToken(source_t *source, token_t *token) +{ + define_t *define; + + while(1) + { + if (!Parse_ReadSourceToken(source, token)) return qfalse; + //check for precompiler directives + if (token->type == TT_PUNCTUATION && *token->string == '#') + { + { + //read the precompiler directive + if (!Parse_ReadDirective(source)) return qfalse; + continue; + } + } + if (token->type == TT_PUNCTUATION && *token->string == '$') + { + { + //read the precompiler directive + if (!Parse_ReadDollarDirective(source)) return qfalse; + continue; + } + } + // recursively concatenate strings that are behind each other still resolving defines + if (token->type == TT_STRING) + { + token_t newtoken; + if (Parse_ReadToken(source, &newtoken)) + { + if (newtoken.type == TT_STRING) + { + token->string[strlen(token->string)-1] = '\0'; + if (strlen(token->string) + strlen(newtoken.string+1) + 1 >= MAX_TOKEN_CHARS) + { + Parse_SourceError(source, "string longer than MAX_TOKEN_CHARS %d\n", MAX_TOKEN_CHARS); + return qfalse; + } + strcat(token->string, newtoken.string+1); + } + else + { + Parse_UnreadToken(source, &newtoken); + } + } + } + //if skipping source because of conditional compilation + if (source->skip) continue; + //if the token is a name + if (token->type == TT_NAME) + { + //check if the name is a define macro + define = Parse_FindHashedDefine(source->definehash, token->string); + //if it is a define macro + if (define) + { + //expand the defined macro + if (!Parse_ExpandDefineIntoSource(source, token, define)) return qfalse; + continue; + } + } + //copy token for unreading + Com_Memcpy(&source->token, token, sizeof(token_t)); + //found a token + return qtrue; + } +} + +/* +=============== +Parse_DefineFromString +=============== +*/ +static define_t *Parse_DefineFromString(char *string) +{ + script_t *script; + source_t src; + token_t *t; + int res, i; + define_t *def; + + script = Parse_LoadScriptMemory(string, strlen(string), "*extern"); + //create a new source + Com_Memset(&src, 0, sizeof(source_t)); + strncpy(src.filename, "*extern", MAX_QPATH); + src.scriptstack = script; + src.definehash = Z_Malloc(DEFINEHASHSIZE * sizeof(define_t *)); + Com_Memset( src.definehash, 0, DEFINEHASHSIZE * sizeof(define_t *)); + //create a define from the source + res = Parse_Directive_define(&src); + //free any tokens if left + for (t = src.tokens; t; t = src.tokens) + { + src.tokens = src.tokens->next; + Parse_FreeToken(t); + } + def = NULL; + for (i = 0; i < DEFINEHASHSIZE; i++) + { + if (src.definehash[i]) + { + def = src.definehash[i]; + break; + } + } + // + Z_Free(src.definehash); + // + Parse_FreeScript(script); + //if the define was created succesfully + if (res > 0) return def; + //free the define is created + if (src.defines) Parse_FreeDefine(def); + // + return NULL; +} + +/* +=============== +Parse_AddGlobalDefine + +add a globals define that will be added to all opened sources +=============== +*/ +int Parse_AddGlobalDefine(char *string) +{ + define_t *define; + + define = Parse_DefineFromString(string); + if (!define) return qfalse; + define->next = globaldefines; + globaldefines = define; + return qtrue; +} + +/* +=============== +Parse_CopyDefine +=============== +*/ +static define_t *Parse_CopyDefine(source_t *source, define_t *define) +{ + define_t *newdefine; + token_t *token, *newtoken, *lasttoken; + + newdefine = (define_t *) Z_Malloc(sizeof(define_t) + strlen(define->name) + 1); + //copy the define name + newdefine->name = (char *) newdefine + sizeof(define_t); + strcpy(newdefine->name, define->name); + newdefine->flags = define->flags; + newdefine->builtin = define->builtin; + newdefine->numparms = define->numparms; + //the define is not linked + newdefine->next = NULL; + newdefine->hashnext = NULL; + //copy the define tokens + newdefine->tokens = NULL; + for (lasttoken = NULL, token = define->tokens; token; token = token->next) + { + newtoken = Parse_CopyToken(token); + newtoken->next = NULL; + if (lasttoken) lasttoken->next = newtoken; + else newdefine->tokens = newtoken; + lasttoken = newtoken; + } + //copy the define parameters + newdefine->parms = NULL; + for (lasttoken = NULL, token = define->parms; token; token = token->next) + { + newtoken = Parse_CopyToken(token); + newtoken->next = NULL; + if (lasttoken) lasttoken->next = newtoken; + else newdefine->parms = newtoken; + lasttoken = newtoken; + } + return newdefine; +} + +/* +=============== +Parse_AddGlobalDefinesToSource +=============== +*/ +static void Parse_AddGlobalDefinesToSource(source_t *source) +{ + define_t *define, *newdefine; + + for (define = globaldefines; define; define = define->next) + { + newdefine = Parse_CopyDefine(source, define); + Parse_AddDefineToHash(newdefine, source->definehash); + } +} + +/* +=============== +Parse_LoadSourceFile +=============== +*/ +static source_t *Parse_LoadSourceFile(const char *filename) +{ + source_t *source; + script_t *script; + + script = Parse_LoadScriptFile(filename); + if (!script) return NULL; + + script->next = NULL; + + source = (source_t *) Z_Malloc(sizeof(source_t)); + Com_Memset(source, 0, sizeof(source_t)); + + strncpy(source->filename, filename, MAX_QPATH); + source->scriptstack = script; + source->tokens = NULL; + source->defines = NULL; + source->indentstack = NULL; + source->skip = 0; + + source->definehash = Z_Malloc(DEFINEHASHSIZE * sizeof(define_t *)); + Com_Memset( source->definehash, 0, DEFINEHASHSIZE * sizeof(define_t *)); + Parse_AddGlobalDefinesToSource(source); + return source; +} + +/* +=============== +Parse_FreeSource +=============== +*/ +static void Parse_FreeSource(source_t *source) +{ + script_t *script; + token_t *token; + define_t *define; + indent_t *indent; + int i; + + //Parse_PrintDefineHashTable(source->definehash); + //free all the scripts + while(source->scriptstack) + { + script = source->scriptstack; + source->scriptstack = source->scriptstack->next; + Parse_FreeScript(script); + } + //free all the tokens + while(source->tokens) + { + token = source->tokens; + source->tokens = source->tokens->next; + Parse_FreeToken(token); + } + for (i = 0; i < DEFINEHASHSIZE; i++) + { + while(source->definehash[i]) + { + define = source->definehash[i]; + source->definehash[i] = source->definehash[i]->hashnext; + Parse_FreeDefine(define); + } + } + //free all indents + while(source->indentstack) + { + indent = source->indentstack; + source->indentstack = source->indentstack->next; + Z_Free(indent); + } + // + if (source->definehash) Z_Free(source->definehash); + //free the source itself + Z_Free(source); +} + +#define MAX_SOURCEFILES 64 + +source_t *sourceFiles[MAX_SOURCEFILES]; + +/* +=============== +Parse_LoadSourceHandle +=============== +*/ +int Parse_LoadSourceHandle(const char *filename) +{ + source_t *source; + int i; + + for (i = 1; i < MAX_SOURCEFILES; i++) + { + if (!sourceFiles[i]) + break; + } + if (i >= MAX_SOURCEFILES) + return 0; + Parse_SetBaseFolder(""); + source = Parse_LoadSourceFile(filename); + if (!source) + return 0; + sourceFiles[i] = source; + return i; +} + +/* +=============== +Parse_FreeSourceHandle +=============== +*/ +int Parse_FreeSourceHandle(int handle) +{ + if (handle < 1 || handle >= MAX_SOURCEFILES) + return qfalse; + if (!sourceFiles[handle]) + return qfalse; + + Parse_FreeSource(sourceFiles[handle]); + sourceFiles[handle] = NULL; + return qtrue; +} + +/* +=============== +Parse_ReadTokenHandle +=============== +*/ +int Parse_ReadTokenHandle(int handle, pc_token_t *pc_token) +{ + token_t token; + int ret; + + if (handle < 1 || handle >= MAX_SOURCEFILES) + return 0; + if (!sourceFiles[handle]) + return 0; + + ret = Parse_ReadToken(sourceFiles[handle], &token); + strcpy(pc_token->string, token.string); + pc_token->type = token.type; + pc_token->subtype = token.subtype; + pc_token->intvalue = token.intvalue; + pc_token->floatvalue = token.floatvalue; + if (pc_token->type == TT_STRING) + Parse_StripDoubleQuotes(pc_token->string); + return ret; +} + +/* +=============== +Parse_SourceFileAndLine +=============== +*/ +int Parse_SourceFileAndLine(int handle, char *filename, int *line) +{ + if (handle < 1 || handle >= MAX_SOURCEFILES) + return qfalse; + if (!sourceFiles[handle]) + return qfalse; + + strcpy(filename, sourceFiles[handle]->filename); + if (sourceFiles[handle]->scriptstack) + *line = sourceFiles[handle]->scriptstack->line; + else + *line = 0; + return qtrue; +} diff --git a/src/qcommon/qcommon.h b/src/qcommon/qcommon.h index f9ca82fc..b21b5958 100644 --- a/src/qcommon/qcommon.h +++ b/src/qcommon/qcommon.h @@ -131,7 +131,6 @@ NET #define MAX_RELIABLE_COMMANDS 128 // max string commands buffered for restransmit typedef enum { - NA_BOT, NA_BAD, // an address lookup failed NA_LOOPBACK, NA_BROADCAST, @@ -1077,6 +1076,12 @@ void Huff_offsetTransmit (huff_t *huff, int ch, byte *fout, int *offset); void Huff_putBit( int bit, byte *fout, int *offset); int Huff_getBit( byte *fout, int *offset); +int Parse_AddGlobalDefine(char *string); +int Parse_LoadSourceHandle(const char *filename); +int Parse_FreeSourceHandle(int handle); +int Parse_ReadTokenHandle(int handle, pc_token_t *pc_token); +int Parse_SourceFileAndLine(int handle, char *filename, int *line); + extern huffman_t clientHuffTables; #define SV_ENCODE_START 4 diff --git a/src/server/sv_bot.c b/src/server/sv_bot.c deleted file mode 100644 index 12eb4563..00000000 --- a/src/server/sv_bot.c +++ /dev/null @@ -1,636 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2000-2006 Tim Angus - -This file is part of Tremulous. - -Tremulous is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Tremulous is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Tremulous; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// sv_bot.c - -#include "server.h" -#include "../botlib/botlib.h" - -typedef struct bot_debugpoly_s -{ - int inuse; - int color; - int numPoints; - vec3_t points[128]; -} bot_debugpoly_t; - -static bot_debugpoly_t *debugpolygons; -int bot_maxdebugpolys; - -extern botlib_export_t *botlib_export; -int bot_enable; - - -/* -================== -SV_BotAllocateClient -================== -*/ -int SV_BotAllocateClient(void) { - int i; - client_t *cl; - - // find a client slot - for ( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ ) { - if ( cl->state == CS_FREE ) { - break; - } - } - - if ( i == sv_maxclients->integer ) { - return -1; - } - - cl->gentity = SV_GentityNum( i ); - cl->gentity->s.number = i; - cl->state = CS_ACTIVE; - cl->lastPacketTime = svs.time; - cl->netchan.remoteAddress.type = NA_BOT; - cl->rate = 16384; - - return i; -} - -/* -================== -SV_BotFreeClient -================== -*/ -void SV_BotFreeClient( int clientNum ) { - client_t *cl; - - if ( clientNum < 0 || clientNum >= sv_maxclients->integer ) { - Com_Error( ERR_DROP, "SV_BotFreeClient: bad clientNum: %i", clientNum ); - } - cl = &svs.clients[clientNum]; - cl->state = CS_FREE; - cl->name[0] = 0; - if ( cl->gentity ) { - cl->gentity->r.svFlags &= ~SVF_BOT; - } -} - -/* -================== -BotDrawDebugPolygons -================== -*/ -void BotDrawDebugPolygons(void (*drawPoly)(int color, int numPoints, float *points), int value) { - static cvar_t *bot_debug, *bot_groundonly, *bot_reachability, *bot_highlightarea; - bot_debugpoly_t *poly; - int i, parm0; - - if (!debugpolygons) - return; - //bot debugging - if (!bot_debug) bot_debug = Cvar_Get("bot_debug", "0", 0); - // - if (bot_enable && bot_debug->integer) { - //show reachabilities - if (!bot_reachability) bot_reachability = Cvar_Get("bot_reachability", "0", 0); - //show ground faces only - if (!bot_groundonly) bot_groundonly = Cvar_Get("bot_groundonly", "1", 0); - //get the hightlight area - if (!bot_highlightarea) bot_highlightarea = Cvar_Get("bot_highlightarea", "0", 0); - // - parm0 = 0; - if (svs.clients[0].lastUsercmd.buttons & BUTTON_ATTACK) parm0 |= 1; - if (bot_reachability->integer) parm0 |= 2; - if (bot_groundonly->integer) parm0 |= 4; - botlib_export->BotLibVarSet("bot_highlightarea", bot_highlightarea->string); - botlib_export->Test(parm0, NULL, svs.clients[0].gentity->r.currentOrigin, - svs.clients[0].gentity->r.currentAngles); - } //end if - //draw all debug polys - for (i = 0; i < bot_maxdebugpolys; i++) { - poly = &debugpolygons[i]; - if (!poly->inuse) continue; - drawPoly(poly->color, poly->numPoints, (float *) poly->points); - //Com_Printf("poly %i, numpoints = %d\n", i, poly->numPoints); - } -} - -/* -================== -BotImport_Print -================== -*/ -void QDECL BotImport_Print(int type, char *fmt, ...) -{ - char str[2048]; - va_list ap; - - va_start(ap, fmt); - vsprintf(str, fmt, ap); - va_end(ap); - - switch(type) { - case PRT_MESSAGE: { - Com_Printf("%s", str); - break; - } - case PRT_WARNING: { - Com_Printf(S_COLOR_YELLOW "Warning: %s", str); - break; - } - case PRT_ERROR: { - Com_Printf(S_COLOR_RED "Error: %s", str); - break; - } - case PRT_FATAL: { - Com_Printf(S_COLOR_RED "Fatal: %s", str); - break; - } - case PRT_EXIT: { - Com_Error(ERR_DROP, S_COLOR_RED "Exit: %s", str); - break; - } - default: { - Com_Printf("unknown print type\n"); - break; - } - } -} - -/* -================== -BotImport_Trace -================== -*/ -void BotImport_Trace(bsp_trace_t *bsptrace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int passent, int contentmask) { - trace_t trace; - - SV_Trace(&trace, start, mins, maxs, end, passent, contentmask, qfalse); - //copy the trace information - bsptrace->allsolid = trace.allsolid; - bsptrace->startsolid = trace.startsolid; - bsptrace->fraction = trace.fraction; - VectorCopy(trace.endpos, bsptrace->endpos); - bsptrace->plane.dist = trace.plane.dist; - VectorCopy(trace.plane.normal, bsptrace->plane.normal); - bsptrace->plane.signbits = trace.plane.signbits; - bsptrace->plane.type = trace.plane.type; - bsptrace->surface.value = trace.surfaceFlags; - bsptrace->ent = trace.entityNum; - bsptrace->exp_dist = 0; - bsptrace->sidenum = 0; - bsptrace->contents = 0; -} - -/* -================== -BotImport_EntityTrace -================== -*/ -void BotImport_EntityTrace(bsp_trace_t *bsptrace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int entnum, int contentmask) { - trace_t trace; - - SV_ClipToEntity(&trace, start, mins, maxs, end, entnum, contentmask, qfalse); - //copy the trace information - bsptrace->allsolid = trace.allsolid; - bsptrace->startsolid = trace.startsolid; - bsptrace->fraction = trace.fraction; - VectorCopy(trace.endpos, bsptrace->endpos); - bsptrace->plane.dist = trace.plane.dist; - VectorCopy(trace.plane.normal, bsptrace->plane.normal); - bsptrace->plane.signbits = trace.plane.signbits; - bsptrace->plane.type = trace.plane.type; - bsptrace->surface.value = trace.surfaceFlags; - bsptrace->ent = trace.entityNum; - bsptrace->exp_dist = 0; - bsptrace->sidenum = 0; - bsptrace->contents = 0; -} - - -/* -================== -BotImport_PointContents -================== -*/ -int BotImport_PointContents(vec3_t point) { - return SV_PointContents(point, -1); -} - -/* -================== -BotImport_inPVS -================== -*/ -int BotImport_inPVS(vec3_t p1, vec3_t p2) { - return SV_inPVS (p1, p2); -} - -/* -================== -BotImport_BSPEntityData -================== -*/ -char *BotImport_BSPEntityData(void) { - return CM_EntityString(); -} - -/* -================== -BotImport_BSPModelMinsMaxsOrigin -================== -*/ -void BotImport_BSPModelMinsMaxsOrigin(int modelnum, vec3_t angles, vec3_t outmins, vec3_t outmaxs, vec3_t origin) { - clipHandle_t h; - vec3_t mins, maxs; - float max; - int i; - - h = CM_InlineModel(modelnum); - CM_ModelBounds(h, mins, maxs); - //if the model is rotated - if ((angles[0] || angles[1] || angles[2])) { - // expand for rotation - - max = RadiusFromBounds(mins, maxs); - for (i = 0; i < 3; i++) { - mins[i] = -max; - maxs[i] = max; - } - } - if (outmins) VectorCopy(mins, outmins); - if (outmaxs) VectorCopy(maxs, outmaxs); - if (origin) VectorClear(origin); -} - -/* -================== -BotImport_GetMemory -================== -*/ -void *BotImport_GetMemory(int size) { - void *ptr; - - ptr = Z_TagMalloc( size, TAG_BOTLIB ); - return ptr; -} - -/* -================== -BotImport_FreeMemory -================== -*/ -void BotImport_FreeMemory(void *ptr) { - Z_Free(ptr); -} - -/* -================= -BotImport_HunkAlloc -================= -*/ -void *BotImport_HunkAlloc( int size ) { - if( Hunk_CheckMark() ) { - Com_Error( ERR_DROP, "SV_Bot_HunkAlloc: Alloc with marks already set\n" ); - } - return Hunk_Alloc( size, h_high ); -} - -/* -================== -BotImport_DebugPolygonCreate -================== -*/ -int BotImport_DebugPolygonCreate(int color, int numPoints, vec3_t *points) { - bot_debugpoly_t *poly; - int i; - - if (!debugpolygons) - return 0; - - for (i = 1; i < bot_maxdebugpolys; i++) { - if (!debugpolygons[i].inuse) - break; - } - if (i >= bot_maxdebugpolys) - return 0; - poly = &debugpolygons[i]; - poly->inuse = qtrue; - poly->color = color; - poly->numPoints = numPoints; - Com_Memcpy(poly->points, points, numPoints * sizeof(vec3_t)); - // - return i; -} - -/* -================== -BotImport_DebugPolygonShow -================== -*/ -void BotImport_DebugPolygonShow(int id, int color, int numPoints, vec3_t *points) { - bot_debugpoly_t *poly; - - if (!debugpolygons) return; - poly = &debugpolygons[id]; - poly->inuse = qtrue; - poly->color = color; - poly->numPoints = numPoints; - Com_Memcpy(poly->points, points, numPoints * sizeof(vec3_t)); -} - -/* -================== -BotImport_DebugPolygonDelete -================== -*/ -void BotImport_DebugPolygonDelete(int id) -{ - if (!debugpolygons) return; - debugpolygons[id].inuse = qfalse; -} - -/* -================== -BotImport_DebugLineCreate -================== -*/ -int BotImport_DebugLineCreate(void) { - vec3_t points[1]; - return BotImport_DebugPolygonCreate(0, 0, points); -} - -/* -================== -BotImport_DebugLineDelete -================== -*/ -void BotImport_DebugLineDelete(int line) { - BotImport_DebugPolygonDelete(line); -} - -/* -================== -BotImport_DebugLineShow -================== -*/ -void BotImport_DebugLineShow(int line, vec3_t start, vec3_t end, int color) { - vec3_t points[4], dir, cross, up = {0, 0, 1}; - float dot; - - VectorCopy(start, points[0]); - VectorCopy(start, points[1]); - //points[1][2] -= 2; - VectorCopy(end, points[2]); - //points[2][2] -= 2; - VectorCopy(end, points[3]); - - - VectorSubtract(end, start, dir); - VectorNormalize(dir); - dot = DotProduct(dir, up); - if (dot > 0.99 || dot < -0.99) VectorSet(cross, 1, 0, 0); - else CrossProduct(dir, up, cross); - - VectorNormalize(cross); - - VectorMA(points[0], 2, cross, points[0]); - VectorMA(points[1], -2, cross, points[1]); - VectorMA(points[2], -2, cross, points[2]); - VectorMA(points[3], 2, cross, points[3]); - - BotImport_DebugPolygonShow(line, color, 4, points); -} - -/* -================== -SV_BotClientCommand -================== -*/ -void BotClientCommand( int client, char *command ) { - SV_ExecuteClientCommand( &svs.clients[client], command, qtrue ); -} - -/* -================== -SV_BotFrame -================== -*/ -void SV_BotFrame( int time ) { - if (!bot_enable) return; - //NOTE: maybe the game is already shutdown - if (!gvm) return; - VM_Call( gvm, BOTAI_START_FRAME, time ); -} - -/* -=============== -SV_BotLibSetup -=============== -*/ -int SV_BotLibSetup( void ) { - if (!bot_enable) { - return 0; - } - - if ( !botlib_export ) { - Com_Printf( S_COLOR_RED "Error: SV_BotLibSetup without SV_BotInitBotLib\n" ); - return -1; - } - - return botlib_export->BotLibSetup(); -} - -/* -=============== -SV_ShutdownBotLib - -Called when either the entire server is being killed, or -it is changing to a different game directory. -=============== -*/ -int SV_BotLibShutdown( void ) { - - if ( !botlib_export ) { - return -1; - } - - return botlib_export->BotLibShutdown(); -} - -/* -================== -SV_BotInitCvars -================== -*/ -void SV_BotInitCvars(void) { - - Cvar_Get("bot_enable", "1", 0); //enable the bot - Cvar_Get("bot_developer", "0", CVAR_CHEAT); //bot developer mode - Cvar_Get("bot_debug", "0", CVAR_CHEAT); //enable bot debugging - Cvar_Get("bot_maxdebugpolys", "2", 0); //maximum number of debug polys - Cvar_Get("bot_groundonly", "1", 0); //only show ground faces of areas - Cvar_Get("bot_reachability", "0", 0); //show all reachabilities to other areas - Cvar_Get("bot_visualizejumppads", "0", CVAR_CHEAT); //show jumppads - Cvar_Get("bot_forceclustering", "0", 0); //force cluster calculations - Cvar_Get("bot_forcereachability", "0", 0); //force reachability calculations - Cvar_Get("bot_forcewrite", "0", 0); //force writing aas file - Cvar_Get("bot_aasoptimize", "0", 0); //no aas file optimisation - Cvar_Get("bot_saveroutingcache", "0", 0); //save routing cache - Cvar_Get("bot_thinktime", "100", CVAR_CHEAT); //msec the bots thinks - Cvar_Get("bot_reloadcharacters", "0", 0); //reload the bot characters each time - Cvar_Get("bot_testichat", "0", 0); //test ichats - Cvar_Get("bot_testrchat", "0", 0); //test rchats - Cvar_Get("bot_testsolid", "0", CVAR_CHEAT); //test for solid areas - Cvar_Get("bot_testclusters", "0", CVAR_CHEAT); //test the AAS clusters - Cvar_Get("bot_fastchat", "0", 0); //fast chatting bots - Cvar_Get("bot_nochat", "0", 0); //disable chats - Cvar_Get("bot_pause", "0", CVAR_CHEAT); //pause the bots thinking - Cvar_Get("bot_report", "0", CVAR_CHEAT); //get a full report in ctf - Cvar_Get("bot_grapple", "0", 0); //enable grapple - Cvar_Get("bot_rocketjump", "1", 0); //enable rocket jumping - Cvar_Get("bot_challenge", "0", 0); //challenging bot - Cvar_Get("bot_minplayers", "0", 0); //minimum players in a team or the game - Cvar_Get("bot_interbreedchar", "", CVAR_CHEAT); //bot character used for interbreeding - Cvar_Get("bot_interbreedbots", "10", CVAR_CHEAT); //number of bots used for interbreeding - Cvar_Get("bot_interbreedcycle", "20", CVAR_CHEAT); //bot interbreeding cycle - Cvar_Get("bot_interbreedwrite", "", CVAR_CHEAT); //write interbreeded bots to this file -} - -/* -================== -SV_BotInitBotLib -================== -*/ -void SV_BotInitBotLib(void) { - botlib_import_t botlib_import; - - if ( !Cvar_VariableValue("fs_restrict") && !Sys_CheckCD() ) { - Com_Error( ERR_NEED_CD, "Game CD not in drive" ); - } - - if (debugpolygons) Z_Free(debugpolygons); - bot_maxdebugpolys = Cvar_VariableIntegerValue("bot_maxdebugpolys"); - debugpolygons = Z_Malloc(sizeof(bot_debugpoly_t) * bot_maxdebugpolys); - - botlib_import.Print = BotImport_Print; - botlib_import.Trace = BotImport_Trace; - botlib_import.EntityTrace = BotImport_EntityTrace; - botlib_import.PointContents = BotImport_PointContents; - botlib_import.inPVS = BotImport_inPVS; - botlib_import.BSPEntityData = BotImport_BSPEntityData; - botlib_import.BSPModelMinsMaxsOrigin = BotImport_BSPModelMinsMaxsOrigin; - botlib_import.BotClientCommand = BotClientCommand; - - //memory management - botlib_import.GetMemory = BotImport_GetMemory; - botlib_import.FreeMemory = BotImport_FreeMemory; - botlib_import.AvailableMemory = Z_AvailableMemory; - botlib_import.HunkAlloc = BotImport_HunkAlloc; - - // file system access - botlib_import.FS_FOpenFile = FS_FOpenFileByMode; - botlib_import.FS_Read = FS_Read2; - botlib_import.FS_Write = FS_Write; - botlib_import.FS_FCloseFile = FS_FCloseFile; - botlib_import.FS_Seek = FS_Seek; - - //debug lines - botlib_import.DebugLineCreate = BotImport_DebugLineCreate; - botlib_import.DebugLineDelete = BotImport_DebugLineDelete; - botlib_import.DebugLineShow = BotImport_DebugLineShow; - - //debug polygons - botlib_import.DebugPolygonCreate = BotImport_DebugPolygonCreate; - botlib_import.DebugPolygonDelete = BotImport_DebugPolygonDelete; - - botlib_export = (botlib_export_t *)GetBotLibAPI( BOTLIB_API_VERSION, &botlib_import ); - assert(botlib_export); // bk001129 - somehow we end up with a zero import. -} - - -// -// * * * BOT AI CODE IS BELOW THIS POINT * * * -// - -/* -================== -SV_BotGetConsoleMessage -================== -*/ -int SV_BotGetConsoleMessage( int client, char *buf, int size ) -{ - client_t *cl; - int index; - - cl = &svs.clients[client]; - cl->lastPacketTime = svs.time; - - if ( cl->reliableAcknowledge == cl->reliableSequence ) { - return qfalse; - } - - cl->reliableAcknowledge++; - index = cl->reliableAcknowledge & ( MAX_RELIABLE_COMMANDS - 1 ); - - if ( !cl->reliableCommands[index][0] ) { - return qfalse; - } - - Q_strncpyz( buf, cl->reliableCommands[index], size ); - return qtrue; -} - -#if 0 -/* -================== -EntityInPVS -================== -*/ -int EntityInPVS( int client, int entityNum ) { - client_t *cl; - clientSnapshot_t *frame; - int i; - - cl = &svs.clients[client]; - frame = &cl->frames[cl->netchan.outgoingSequence & PACKET_MASK]; - for ( i = 0; i < frame->num_entities; i++ ) { - if ( svs.snapshotEntities[(frame->first_entity + i) % svs.numSnapshotEntities].number == entityNum ) { - return qtrue; - } - } - return qfalse; -} -#endif - -/* -================== -SV_BotGetSnapshotEntity -================== -*/ -int SV_BotGetSnapshotEntity( int client, int sequence ) { - client_t *cl; - clientSnapshot_t *frame; - - cl = &svs.clients[client]; - frame = &cl->frames[cl->netchan.outgoingSequence & PACKET_MASK]; - if (sequence < 0 || sequence >= frame->num_entities) { - return -1; - } - return svs.snapshotEntities[(frame->first_entity + sequence) % svs.numSnapshotEntities].number; -} - diff --git a/src/server/sv_ccmds.c b/src/server/sv_ccmds.c index 0e016056..a89b0f21 100644 --- a/src/server/sv_ccmds.c +++ b/src/server/sv_ccmds.c @@ -210,7 +210,6 @@ static void SV_MapRestart_f( void ) { int i; client_t *client; char *denied; - qboolean isBot; int delay; // make sure we aren't restarting twice in the same frame @@ -290,17 +289,11 @@ static void SV_MapRestart_f( void ) { continue; } - if ( client->netchan.remoteAddress.type == NA_BOT ) { - isBot = qtrue; - } else { - isBot = qfalse; - } - // add the map_restart command SV_AddServerCommand( client, "map_restart\n" ); // connect the client again, without the firstTime flag - denied = VM_ExplicitArgPtr( gvm, VM_Call( gvm, GAME_CLIENT_CONNECT, i, qfalse, isBot ) ); + denied = VM_ExplicitArgPtr( gvm, VM_Call( gvm, GAME_CLIENT_CONNECT, i, qfalse ) ); if ( denied ) { // this generally shouldn't happen, because the client // was connected before the level change diff --git a/src/server/sv_client.c b/src/server/sv_client.c index fe7cc905..3ee193dd 100644 --- a/src/server/sv_client.c +++ b/src/server/sv_client.c @@ -233,22 +233,8 @@ void SV_DirectConnect( netadr_t from ) { if ( !newcl ) { if ( NET_IsLocalAddress( from ) ) { - count = 0; - for ( i = startIndex; i < sv_maxclients->integer ; i++ ) { - cl = &svs.clients[i]; - if (cl->netchan.remoteAddress.type == NA_BOT) { - count++; - } - } - // if they're all bots - if (count >= sv_maxclients->integer - startIndex) { - SV_DropClient(&svs.clients[sv_maxclients->integer - 1], "only bots on server"); - newcl = &svs.clients[sv_maxclients->integer - 1]; - } - else { - Com_Error( ERR_FATAL, "server is full on local connect\n" ); - return; - } + Com_Error( ERR_FATAL, "server is full on local connect\n" ); + return; } else { NET_OutOfBandPrint( NS_SERVER, from, "print\nServer is full" ); @@ -282,7 +268,7 @@ gotnewcl: Q_strncpyz( newcl->userinfo, userinfo, sizeof(newcl->userinfo) ); // get the game a chance to reject this connection or modify the userinfo - denied = VM_Call( gvm, GAME_CLIENT_CONNECT, clientNum, qtrue, qfalse ); // firstTime = qtrue + denied = VM_Call( gvm, GAME_CLIENT_CONNECT, clientNum, qtrue ); // firstTime = qtrue if ( denied ) { // we can't just use VM_ArgPtr, because that is only valid inside a VM_Call char *str = VM_ExplicitArgPtr( gvm, denied ); @@ -340,15 +326,13 @@ void SV_DropClient( client_t *drop, const char *reason ) { return; // already dropped } - if (drop->netchan.remoteAddress.type != NA_BOT) { - // see if we already have a challenge for this ip - challenge = &svs.challenges[0]; + // see if we already have a challenge for this ip + challenge = &svs.challenges[0]; - for (i = 0 ; i < MAX_CHALLENGES ; i++, challenge++) { - if ( NET_CompareAdr( drop->netchan.remoteAddress, challenge->adr ) ) { - challenge->connected = qfalse; - break; - } + for (i = 0 ; i < MAX_CHALLENGES ; i++, challenge++) { + if ( NET_CompareAdr( drop->netchan.remoteAddress, challenge->adr ) ) { + challenge->connected = qfalse; + break; } } @@ -373,10 +357,6 @@ void SV_DropClient( client_t *drop, const char *reason ) { // add the disconnect command SV_SendServerCommand( drop, "disconnect \"%s\"", reason); - if ( drop->netchan.remoteAddress.type == NA_BOT ) { - SV_BotFreeClient( drop - svs.clients ); - } - // nuke user info SV_SetUserinfo( drop - svs.clients, "" ); diff --git a/src/server/sv_game.c b/src/server/sv_game.c index cd6354f5..82a02184 100644 --- a/src/server/sv_game.c +++ b/src/server/sv_game.c @@ -24,10 +24,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "server.h" -#include "../botlib/botlib.h" - -botlib_export_t *botlib_export; - void SV_GameError( const char *string ) { Com_Error( ERR_DROP, "%s", string ); } @@ -413,12 +409,6 @@ intptr_t SV_GameSystemCalls( intptr_t *args ) { case G_AREAS_CONNECTED: return CM_AreasConnected( args[1], args[2] ); - case G_BOT_ALLOCATE_CLIENT: - return SV_BotAllocateClient(); - case G_BOT_FREE_CLIENT: - SV_BotFreeClient( args[1] ); - return 0; - case G_GET_USERCMD: SV_GetUsercmd( args[1], VMA(2) ); return 0; @@ -435,11 +425,6 @@ intptr_t SV_GameSystemCalls( intptr_t *args ) { } } - case G_DEBUG_POLYGON_CREATE: - return BotImport_DebugPolygonCreate( args[1], args[2], VMA(3) ); - case G_DEBUG_POLYGON_DELETE: - BotImport_DebugPolygonDelete( args[1] ); - return 0; case G_REAL_TIME: return Com_RealTime( VMA(1) ); case G_SNAPVECTOR: @@ -450,370 +435,18 @@ intptr_t SV_GameSystemCalls( intptr_t *args ) { SV_MasterGameStat( VMA(1) ); return 0; - //==================================== - - case BOTLIB_SETUP: - return SV_BotLibSetup(); - case BOTLIB_SHUTDOWN: - return SV_BotLibShutdown(); - case BOTLIB_LIBVAR_SET: - return botlib_export->BotLibVarSet( VMA(1), VMA(2) ); - case BOTLIB_LIBVAR_GET: - return botlib_export->BotLibVarGet( VMA(1), VMA(2), args[3] ); - - case BOTLIB_PC_ADD_GLOBAL_DEFINE: - return botlib_export->PC_AddGlobalDefine( VMA(1) ); - case BOTLIB_PC_LOAD_SOURCE: - return botlib_export->PC_LoadSourceHandle( VMA(1) ); - case BOTLIB_PC_FREE_SOURCE: - return botlib_export->PC_FreeSourceHandle( args[1] ); - case BOTLIB_PC_READ_TOKEN: - return botlib_export->PC_ReadTokenHandle( args[1], VMA(2) ); - case BOTLIB_PC_SOURCE_FILE_AND_LINE: - return botlib_export->PC_SourceFileAndLine( args[1], VMA(2), VMA(3) ); - - case BOTLIB_START_FRAME: - return botlib_export->BotLibStartFrame( VMF(1) ); - case BOTLIB_LOAD_MAP: - return botlib_export->BotLibLoadMap( VMA(1) ); - case BOTLIB_UPDATENTITY: - return botlib_export->BotLibUpdateEntity( args[1], VMA(2) ); - case BOTLIB_TEST: - return botlib_export->Test( args[1], VMA(2), VMA(3), VMA(4) ); - - case BOTLIB_GET_SNAPSHOT_ENTITY: - return SV_BotGetSnapshotEntity( args[1], args[2] ); - case BOTLIB_GET_CONSOLE_MESSAGE: - return SV_BotGetConsoleMessage( args[1], VMA(2), args[3] ); - case BOTLIB_USER_COMMAND: - SV_ClientThink( &svs.clients[args[1]], VMA(2) ); - return 0; - - case BOTLIB_AAS_BBOX_AREAS: - return botlib_export->aas.AAS_BBoxAreas( VMA(1), VMA(2), VMA(3), args[4] ); - case BOTLIB_AAS_AREA_INFO: - return botlib_export->aas.AAS_AreaInfo( args[1], VMA(2) ); - case BOTLIB_AAS_ALTERNATIVE_ROUTE_GOAL: - return botlib_export->aas.AAS_AlternativeRouteGoals( VMA(1), args[2], VMA(3), args[4], args[5], VMA(6), args[7], args[8] ); - case BOTLIB_AAS_ENTITY_INFO: - botlib_export->aas.AAS_EntityInfo( args[1], VMA(2) ); - return 0; - - case BOTLIB_AAS_INITIALIZED: - return botlib_export->aas.AAS_Initialized(); - case BOTLIB_AAS_PRESENCE_TYPE_BOUNDING_BOX: - botlib_export->aas.AAS_PresenceTypeBoundingBox( args[1], VMA(2), VMA(3) ); - return 0; - case BOTLIB_AAS_TIME: - return FloatAsInt( botlib_export->aas.AAS_Time() ); - - case BOTLIB_AAS_POINT_AREA_NUM: - return botlib_export->aas.AAS_PointAreaNum( VMA(1) ); - case BOTLIB_AAS_POINT_REACHABILITY_AREA_INDEX: - return botlib_export->aas.AAS_PointReachabilityAreaIndex( VMA(1) ); - case BOTLIB_AAS_TRACE_AREAS: - return botlib_export->aas.AAS_TraceAreas( VMA(1), VMA(2), VMA(3), VMA(4), args[5] ); - - case BOTLIB_AAS_POINT_CONTENTS: - return botlib_export->aas.AAS_PointContents( VMA(1) ); - case BOTLIB_AAS_NEXT_BSP_ENTITY: - return botlib_export->aas.AAS_NextBSPEntity( args[1] ); - case BOTLIB_AAS_VALUE_FOR_BSP_EPAIR_KEY: - return botlib_export->aas.AAS_ValueForBSPEpairKey( args[1], VMA(2), VMA(3), args[4] ); - case BOTLIB_AAS_VECTOR_FOR_BSP_EPAIR_KEY: - return botlib_export->aas.AAS_VectorForBSPEpairKey( args[1], VMA(2), VMA(3) ); - case BOTLIB_AAS_FLOAT_FOR_BSP_EPAIR_KEY: - return botlib_export->aas.AAS_FloatForBSPEpairKey( args[1], VMA(2), VMA(3) ); - case BOTLIB_AAS_INT_FOR_BSP_EPAIR_KEY: - return botlib_export->aas.AAS_IntForBSPEpairKey( args[1], VMA(2), VMA(3) ); - - case BOTLIB_AAS_AREA_REACHABILITY: - return botlib_export->aas.AAS_AreaReachability( args[1] ); - - case BOTLIB_AAS_AREA_TRAVEL_TIME_TO_GOAL_AREA: - return botlib_export->aas.AAS_AreaTravelTimeToGoalArea( args[1], VMA(2), args[3], args[4] ); - case BOTLIB_AAS_ENABLE_ROUTING_AREA: - return botlib_export->aas.AAS_EnableRoutingArea( args[1], args[2] ); - case BOTLIB_AAS_PREDICT_ROUTE: - return botlib_export->aas.AAS_PredictRoute( VMA(1), args[2], VMA(3), args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11] ); - - case BOTLIB_AAS_SWIMMING: - return botlib_export->aas.AAS_Swimming( VMA(1) ); - case BOTLIB_AAS_PREDICT_CLIENT_MOVEMENT: - return botlib_export->aas.AAS_PredictClientMovement( VMA(1), args[2], VMA(3), args[4], args[5], - VMA(6), VMA(7), args[8], args[9], VMF(10), args[11], args[12], args[13] ); - - case BOTLIB_EA_SAY: - botlib_export->ea.EA_Say( args[1], VMA(2) ); - return 0; - case BOTLIB_EA_SAY_TEAM: - botlib_export->ea.EA_SayTeam( args[1], VMA(2) ); - return 0; - case BOTLIB_EA_COMMAND: - botlib_export->ea.EA_Command( args[1], VMA(2) ); - return 0; - - case BOTLIB_EA_ACTION: - botlib_export->ea.EA_Action( args[1], args[2] ); - break; - case BOTLIB_EA_GESTURE: - botlib_export->ea.EA_Gesture( args[1] ); - return 0; - case BOTLIB_EA_TALK: - botlib_export->ea.EA_Talk( args[1] ); - return 0; - case BOTLIB_EA_ATTACK: - botlib_export->ea.EA_Attack( args[1] ); - return 0; - case BOTLIB_EA_USE: - botlib_export->ea.EA_Use( args[1] ); - return 0; - case BOTLIB_EA_RESPAWN: - botlib_export->ea.EA_Respawn( args[1] ); - return 0; - case BOTLIB_EA_CROUCH: - botlib_export->ea.EA_Crouch( args[1] ); - return 0; - case BOTLIB_EA_MOVE_UP: - botlib_export->ea.EA_MoveUp( args[1] ); - return 0; - case BOTLIB_EA_MOVE_DOWN: - botlib_export->ea.EA_MoveDown( args[1] ); - return 0; - case BOTLIB_EA_MOVE_FORWARD: - botlib_export->ea.EA_MoveForward( args[1] ); - return 0; - case BOTLIB_EA_MOVE_BACK: - botlib_export->ea.EA_MoveBack( args[1] ); - return 0; - case BOTLIB_EA_MOVE_LEFT: - botlib_export->ea.EA_MoveLeft( args[1] ); - return 0; - case BOTLIB_EA_MOVE_RIGHT: - botlib_export->ea.EA_MoveRight( args[1] ); - return 0; - - case BOTLIB_EA_SELECT_WEAPON: - botlib_export->ea.EA_SelectWeapon( args[1], args[2] ); - return 0; - case BOTLIB_EA_JUMP: - botlib_export->ea.EA_Jump( args[1] ); - return 0; - case BOTLIB_EA_DELAYED_JUMP: - botlib_export->ea.EA_DelayedJump( args[1] ); - return 0; - case BOTLIB_EA_MOVE: - botlib_export->ea.EA_Move( args[1], VMA(2), VMF(3) ); - return 0; - case BOTLIB_EA_VIEW: - botlib_export->ea.EA_View( args[1], VMA(2) ); - return 0; - - case BOTLIB_EA_END_REGULAR: - botlib_export->ea.EA_EndRegular( args[1], VMF(2) ); - return 0; - case BOTLIB_EA_GET_INPUT: - botlib_export->ea.EA_GetInput( args[1], VMF(2), VMA(3) ); - return 0; - case BOTLIB_EA_RESET_INPUT: - botlib_export->ea.EA_ResetInput( args[1] ); - return 0; - - case BOTLIB_AI_LOAD_CHARACTER: - return botlib_export->ai.BotLoadCharacter( VMA(1), VMF(2) ); - case BOTLIB_AI_FREE_CHARACTER: - botlib_export->ai.BotFreeCharacter( args[1] ); - return 0; - case BOTLIB_AI_CHARACTERISTIC_FLOAT: - return FloatAsInt( botlib_export->ai.Characteristic_Float( args[1], args[2] ) ); - case BOTLIB_AI_CHARACTERISTIC_BFLOAT: - return FloatAsInt( botlib_export->ai.Characteristic_BFloat( args[1], args[2], VMF(3), VMF(4) ) ); - case BOTLIB_AI_CHARACTERISTIC_INTEGER: - return botlib_export->ai.Characteristic_Integer( args[1], args[2] ); - case BOTLIB_AI_CHARACTERISTIC_BINTEGER: - return botlib_export->ai.Characteristic_BInteger( args[1], args[2], args[3], args[4] ); - case BOTLIB_AI_CHARACTERISTIC_STRING: - botlib_export->ai.Characteristic_String( args[1], args[2], VMA(3), args[4] ); - return 0; + //==================================== - case BOTLIB_AI_ALLOC_CHAT_STATE: - return botlib_export->ai.BotAllocChatState(); - case BOTLIB_AI_FREE_CHAT_STATE: - botlib_export->ai.BotFreeChatState( args[1] ); - return 0; - case BOTLIB_AI_QUEUE_CONSOLE_MESSAGE: - botlib_export->ai.BotQueueConsoleMessage( args[1], args[2], VMA(3) ); - return 0; - case BOTLIB_AI_REMOVE_CONSOLE_MESSAGE: - botlib_export->ai.BotRemoveConsoleMessage( args[1], args[2] ); - return 0; - case BOTLIB_AI_NEXT_CONSOLE_MESSAGE: - return botlib_export->ai.BotNextConsoleMessage( args[1], VMA(2) ); - case BOTLIB_AI_NUM_CONSOLE_MESSAGE: - return botlib_export->ai.BotNumConsoleMessages( args[1] ); - case BOTLIB_AI_INITIAL_CHAT: - botlib_export->ai.BotInitialChat( args[1], VMA(2), args[3], VMA(4), VMA(5), VMA(6), VMA(7), VMA(8), VMA(9), VMA(10), VMA(11) ); - return 0; - case BOTLIB_AI_NUM_INITIAL_CHATS: - return botlib_export->ai.BotNumInitialChats( args[1], VMA(2) ); - case BOTLIB_AI_REPLY_CHAT: - return botlib_export->ai.BotReplyChat( args[1], VMA(2), args[3], args[4], VMA(5), VMA(6), VMA(7), VMA(8), VMA(9), VMA(10), VMA(11), VMA(12) ); - case BOTLIB_AI_CHAT_LENGTH: - return botlib_export->ai.BotChatLength( args[1] ); - case BOTLIB_AI_ENTER_CHAT: - botlib_export->ai.BotEnterChat( args[1], args[2], args[3] ); - return 0; - case BOTLIB_AI_GET_CHAT_MESSAGE: - botlib_export->ai.BotGetChatMessage( args[1], VMA(2), args[3] ); - return 0; - case BOTLIB_AI_STRING_CONTAINS: - return botlib_export->ai.StringContains( VMA(1), VMA(2), args[3] ); - case BOTLIB_AI_FIND_MATCH: - return botlib_export->ai.BotFindMatch( VMA(1), VMA(2), args[3] ); - case BOTLIB_AI_MATCH_VARIABLE: - botlib_export->ai.BotMatchVariable( VMA(1), args[2], VMA(3), args[4] ); - return 0; - case BOTLIB_AI_UNIFY_WHITE_SPACES: - botlib_export->ai.UnifyWhiteSpaces( VMA(1) ); - return 0; - case BOTLIB_AI_REPLACE_SYNONYMS: - botlib_export->ai.BotReplaceSynonyms( VMA(1), args[2] ); - return 0; - case BOTLIB_AI_LOAD_CHAT_FILE: - return botlib_export->ai.BotLoadChatFile( args[1], VMA(2), VMA(3) ); - case BOTLIB_AI_SET_CHAT_GENDER: - botlib_export->ai.BotSetChatGender( args[1], args[2] ); - return 0; - case BOTLIB_AI_SET_CHAT_NAME: - botlib_export->ai.BotSetChatName( args[1], VMA(2), args[3] ); - return 0; - - case BOTLIB_AI_RESET_GOAL_STATE: - botlib_export->ai.BotResetGoalState( args[1] ); - return 0; - case BOTLIB_AI_RESET_AVOID_GOALS: - botlib_export->ai.BotResetAvoidGoals( args[1] ); - return 0; - case BOTLIB_AI_REMOVE_FROM_AVOID_GOALS: - botlib_export->ai.BotRemoveFromAvoidGoals( args[1], args[2] ); - return 0; - case BOTLIB_AI_PUSH_GOAL: - botlib_export->ai.BotPushGoal( args[1], VMA(2) ); - return 0; - case BOTLIB_AI_POP_GOAL: - botlib_export->ai.BotPopGoal( args[1] ); - return 0; - case BOTLIB_AI_EMPTY_GOAL_STACK: - botlib_export->ai.BotEmptyGoalStack( args[1] ); - return 0; - case BOTLIB_AI_DUMP_AVOID_GOALS: - botlib_export->ai.BotDumpAvoidGoals( args[1] ); - return 0; - case BOTLIB_AI_DUMP_GOAL_STACK: - botlib_export->ai.BotDumpGoalStack( args[1] ); - return 0; - case BOTLIB_AI_GOAL_NAME: - botlib_export->ai.BotGoalName( args[1], VMA(2), args[3] ); - return 0; - case BOTLIB_AI_GET_TOP_GOAL: - return botlib_export->ai.BotGetTopGoal( args[1], VMA(2) ); - case BOTLIB_AI_GET_SECOND_GOAL: - return botlib_export->ai.BotGetSecondGoal( args[1], VMA(2) ); - case BOTLIB_AI_CHOOSE_LTG_ITEM: - return botlib_export->ai.BotChooseLTGItem( args[1], VMA(2), VMA(3), args[4] ); - case BOTLIB_AI_CHOOSE_NBG_ITEM: - return botlib_export->ai.BotChooseNBGItem( args[1], VMA(2), VMA(3), args[4], VMA(5), VMF(6) ); - case BOTLIB_AI_TOUCHING_GOAL: - return botlib_export->ai.BotTouchingGoal( VMA(1), VMA(2) ); - case BOTLIB_AI_ITEM_GOAL_IN_VIS_BUT_NOT_VISIBLE: - return botlib_export->ai.BotItemGoalInVisButNotVisible( args[1], VMA(2), VMA(3), VMA(4) ); - case BOTLIB_AI_GET_LEVEL_ITEM_GOAL: - return botlib_export->ai.BotGetLevelItemGoal( args[1], VMA(2), VMA(3) ); - case BOTLIB_AI_GET_NEXT_CAMP_SPOT_GOAL: - return botlib_export->ai.BotGetNextCampSpotGoal( args[1], VMA(2) ); - case BOTLIB_AI_GET_MAP_LOCATION_GOAL: - return botlib_export->ai.BotGetMapLocationGoal( VMA(1), VMA(2) ); - case BOTLIB_AI_AVOID_GOAL_TIME: - return FloatAsInt( botlib_export->ai.BotAvoidGoalTime( args[1], args[2] ) ); - case BOTLIB_AI_SET_AVOID_GOAL_TIME: - botlib_export->ai.BotSetAvoidGoalTime( args[1], args[2], VMF(3)); - return 0; - case BOTLIB_AI_INIT_LEVEL_ITEMS: - botlib_export->ai.BotInitLevelItems(); - return 0; - case BOTLIB_AI_UPDATE_ENTITY_ITEMS: - botlib_export->ai.BotUpdateEntityItems(); - return 0; - case BOTLIB_AI_LOAD_ITEM_WEIGHTS: - return botlib_export->ai.BotLoadItemWeights( args[1], VMA(2) ); - case BOTLIB_AI_FREE_ITEM_WEIGHTS: - botlib_export->ai.BotFreeItemWeights( args[1] ); - return 0; - case BOTLIB_AI_INTERBREED_GOAL_FUZZY_LOGIC: - botlib_export->ai.BotInterbreedGoalFuzzyLogic( args[1], args[2], args[3] ); - return 0; - case BOTLIB_AI_SAVE_GOAL_FUZZY_LOGIC: - botlib_export->ai.BotSaveGoalFuzzyLogic( args[1], VMA(2) ); - return 0; - case BOTLIB_AI_MUTATE_GOAL_FUZZY_LOGIC: - botlib_export->ai.BotMutateGoalFuzzyLogic( args[1], VMF(2) ); - return 0; - case BOTLIB_AI_ALLOC_GOAL_STATE: - return botlib_export->ai.BotAllocGoalState( args[1] ); - case BOTLIB_AI_FREE_GOAL_STATE: - botlib_export->ai.BotFreeGoalState( args[1] ); - return 0; - - case BOTLIB_AI_RESET_MOVE_STATE: - botlib_export->ai.BotResetMoveState( args[1] ); - return 0; - case BOTLIB_AI_ADD_AVOID_SPOT: - botlib_export->ai.BotAddAvoidSpot( args[1], VMA(2), VMF(3), args[4] ); - return 0; - case BOTLIB_AI_MOVE_TO_GOAL: - botlib_export->ai.BotMoveToGoal( VMA(1), args[2], VMA(3), args[4] ); - return 0; - case BOTLIB_AI_MOVE_IN_DIRECTION: - return botlib_export->ai.BotMoveInDirection( args[1], VMA(2), VMF(3), args[4] ); - case BOTLIB_AI_RESET_AVOID_REACH: - botlib_export->ai.BotResetAvoidReach( args[1] ); - return 0; - case BOTLIB_AI_RESET_LAST_AVOID_REACH: - botlib_export->ai.BotResetLastAvoidReach( args[1] ); - return 0; - case BOTLIB_AI_REACHABILITY_AREA: - return botlib_export->ai.BotReachabilityArea( VMA(1), args[2] ); - case BOTLIB_AI_MOVEMENT_VIEW_TARGET: - return botlib_export->ai.BotMovementViewTarget( args[1], VMA(2), args[3], VMF(4), VMA(5) ); - case BOTLIB_AI_PREDICT_VISIBLE_POSITION: - return botlib_export->ai.BotPredictVisiblePosition( VMA(1), args[2], VMA(3), args[4], VMA(5) ); - case BOTLIB_AI_ALLOC_MOVE_STATE: - return botlib_export->ai.BotAllocMoveState(); - case BOTLIB_AI_FREE_MOVE_STATE: - botlib_export->ai.BotFreeMoveState( args[1] ); - return 0; - case BOTLIB_AI_INIT_MOVE_STATE: - botlib_export->ai.BotInitMoveState( args[1], VMA(2) ); - return 0; - - case BOTLIB_AI_CHOOSE_BEST_FIGHT_WEAPON: - return botlib_export->ai.BotChooseBestFightWeapon( args[1], VMA(2) ); - case BOTLIB_AI_GET_WEAPON_INFO: - botlib_export->ai.BotGetWeaponInfo( args[1], args[2], VMA(3) ); - return 0; - case BOTLIB_AI_LOAD_WEAPON_WEIGHTS: - return botlib_export->ai.BotLoadWeaponWeights( args[1], VMA(2) ); - case BOTLIB_AI_ALLOC_WEAPON_STATE: - return botlib_export->ai.BotAllocWeaponState(); - case BOTLIB_AI_FREE_WEAPON_STATE: - botlib_export->ai.BotFreeWeaponState( args[1] ); - return 0; - case BOTLIB_AI_RESET_WEAPON_STATE: - botlib_export->ai.BotResetWeaponState( args[1] ); - return 0; - - case BOTLIB_AI_GENETIC_PARENTS_AND_CHILD_SELECTION: - return botlib_export->ai.GeneticParentsAndChildSelection(args[1], VMA(2), VMA(3), VMA(4), VMA(5)); + case G_PARSE_ADD_GLOBAL_DEFINE: + return Parse_AddGlobalDefine( VMA(1) ); + case G_PARSE_LOAD_SOURCE: + return Parse_LoadSourceHandle( VMA(1) ); + case G_PARSE_FREE_SOURCE: + return Parse_FreeSourceHandle( args[1] ); + case G_PARSE_READ_TOKEN: + return Parse_ReadTokenHandle( args[1], VMA(2) ); + case G_PARSE_SOURCE_FILE_AND_LINE: + return Parse_SourceFileAndLine( args[1], VMA(2), VMA(3) ); case TRAP_MEMSET: Com_Memset( VMA(1), args[2], args[3] ); @@ -939,18 +572,6 @@ Called on a normal map change, not on a map_restart =============== */ void SV_InitGameProgs( void ) { - cvar_t *var; - //FIXME these are temp while I make bots run in vm - extern int bot_enable; - - var = Cvar_Get( "bot_enable", "1", CVAR_LATCH ); - if ( var ) { - bot_enable = var->integer; - } - else { - bot_enable = 0; - } - // load the dll or bytecode gvm = VM_Create( "game", SV_GameSystemCalls, Cvar_VariableValue( "vm_game" ) ); if ( !gvm ) { diff --git a/src/server/sv_init.c b/src/server/sv_init.c index 76cb8297..22f45729 100644 --- a/src/server/sv_init.c +++ b/src/server/sv_init.c @@ -348,7 +348,6 @@ This is NOT called for map_restart void SV_SpawnServer( char *server, qboolean killBots ) { int i; int checksum; - qboolean isBot; char systemInfo[16384]; const char *p; @@ -441,7 +440,6 @@ void SV_SpawnServer( char *server, qboolean killBots ) { for (i = 0;i < 3; i++) { VM_Call (gvm, GAME_RUN_FRAME, sv.time); - SV_BotFrame (sv.time); sv.time += 100; svs.time += 100; } @@ -454,51 +452,22 @@ void SV_SpawnServer( char *server, qboolean killBots ) { if (svs.clients[i].state >= CS_CONNECTED) { char *denied; - if ( svs.clients[i].netchan.remoteAddress.type == NA_BOT ) { - if ( killBots ) { - SV_DropClient( &svs.clients[i], "" ); - continue; - } - isBot = qtrue; - } - else { - isBot = qfalse; - } - // connect the client again - denied = VM_ExplicitArgPtr( gvm, VM_Call( gvm, GAME_CLIENT_CONNECT, i, qfalse, isBot ) ); // firstTime = qfalse + denied = VM_ExplicitArgPtr( gvm, VM_Call( gvm, GAME_CLIENT_CONNECT, i, qfalse ) ); // firstTime = qfalse if ( denied ) { // this generally shouldn't happen, because the client // was connected before the level change SV_DropClient( &svs.clients[i], denied ); } else { - if( !isBot ) { - // when we get the next packet from a connected client, - // the new gamestate will be sent - svs.clients[i].state = CS_CONNECTED; - } - else { - client_t *client; - sharedEntity_t *ent; - - client = &svs.clients[i]; - client->state = CS_ACTIVE; - ent = SV_GentityNum( i ); - ent->s.number = i; - client->gentity = ent; - - client->deltaMessage = -1; - client->nextSnapshotTime = svs.time; // generate a snapshot immediately - - VM_Call( gvm, GAME_CLIENT_BEGIN, i ); - } + // when we get the next packet from a connected client, + // the new gamestate will be sent + svs.clients[i].state = CS_CONNECTED; } } } // run another frame to allow things to look at all the players VM_Call (gvm, GAME_RUN_FRAME, sv.time); - SV_BotFrame (sv.time); sv.time += 100; svs.time += 100; @@ -558,8 +527,6 @@ SV_Init Only called at main exe startup, not for each game =============== */ -void SV_BotInitBotLib(void); - void SV_Init (void) { SV_AddOperatorCommands (); @@ -605,12 +572,6 @@ void SV_Init (void) { sv_mapChecksum = Cvar_Get ("sv_mapChecksum", "", CVAR_ROM); sv_lanForceRate = Cvar_Get ("sv_lanForceRate", "1", CVAR_ARCHIVE ); sv_dequeuePeriod = Cvar_Get ("sv_dequeuePeriod", "500", CVAR_ARCHIVE ); - - // initialize bot cvars so they are listed and can be set before loading the botlib - SV_BotInitCvars(); - - // init the botlib here because we need the pre-compiler in the UI - SV_BotInitBotLib(); } diff --git a/src/server/sv_main.c b/src/server/sv_main.c index 2e3135b6..f4d960d9 100644 --- a/src/server/sv_main.c +++ b/src/server/sv_main.c @@ -104,11 +104,6 @@ int SV_ReplacePendingServerCommands( client_t *client, const char *cmd ) { sscanf(client->reliableCommands[ index ], "cs %i", &csnum2); if ( csnum1 == csnum2 ) { Q_strncpyz( client->reliableCommands[ index ], cmd, sizeof( client->reliableCommands[ index ] ) ); - /* - if ( client->netchan.remoteAddress.type != NA_BOT ) { - Com_Printf( "WARNING: client %i removed double pending config string %i: %s\n", client-svs.clients, csnum1, cmd ); - } - */ return qtrue; } } @@ -660,10 +655,6 @@ void SV_CalcPings( void ) { cl->ping = 999; continue; } - if ( cl->gentity->r.svFlags & SVF_BOT ) { - cl->ping = 0; - continue; - } total = 0; count = 0; @@ -756,7 +747,7 @@ qboolean SV_CheckPaused( void ) { // only pause if there is just a single client connected count = 0; for (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) { - if ( cl->state >= CS_CONNECTED && cl->netchan.remoteAddress.type != NA_BOT ) { + if ( cl->state >= CS_CONNECTED ) { count++; } } @@ -809,8 +800,6 @@ void SV_Frame( int msec ) { sv.timeResidual += msec; - if (!com_dedicated->integer) SV_BotFrame (sv.time + sv.timeResidual); - if ( com_dedicated->integer && sv.timeResidual < frameMsec ) { // NET_Sleep will give the OS time slices until either get a packet // or time enough for a server frame has gone by @@ -859,8 +848,6 @@ void SV_Frame( int msec ) { // update ping based on the all received frames SV_CalcPings(); - if (com_dedicated->integer) SV_BotFrame (sv.time); - // run the game simulation in chunks while ( sv.timeResidual >= frameMsec ) { sv.timeResidual -= frameMsec; diff --git a/src/server/sv_snapshot.c b/src/server/sv_snapshot.c index 26e3d31b..cd295edf 100644 --- a/src/server/sv_snapshot.c +++ b/src/server/sv_snapshot.c @@ -625,12 +625,6 @@ void SV_SendClientSnapshot( client_t *client ) { // build the snapshot SV_BuildClientSnapshot( client ); - // bots need to have their snapshots build, but - // the query them directly without needing to be sent - if ( client->gentity && client->gentity->r.svFlags & SVF_BOT ) { - return; - } - MSG_Init (&msg, msg_buf, sizeof(msg_buf)); msg.allowoverflow = qtrue; diff --git a/src/ui/ui_main.c b/src/ui/ui_main.c index 7873fb63..32750a57 100644 --- a/src/ui/ui_main.c +++ b/src/ui/ui_main.c @@ -790,7 +790,7 @@ qboolean Asset_Parse(int handle) { pc_token_t token; const char *tempStr; - if (!trap_PC_ReadToken(handle, &token)) + if (!trap_Parse_ReadToken(handle, &token)) return qfalse; if (Q_stricmp(token.string, "{") != 0) { return qfalse; @@ -800,7 +800,7 @@ qboolean Asset_Parse(int handle) { memset(&token, 0, sizeof(pc_token_t)); - if (!trap_PC_ReadToken(handle, &token)) + if (!trap_Parse_ReadToken(handle, &token)) return qfalse; if (Q_stricmp(token.string, "}") == 0) { @@ -958,14 +958,14 @@ void UI_ParseMenu(const char *menuFile) { /*Com_Printf("Parsing menu file:%s\n", menuFile);*/ - handle = trap_PC_LoadSource(menuFile); + handle = trap_Parse_LoadSource(menuFile); if (!handle) { return; } while ( 1 ) { memset(&token, 0, sizeof(pc_token_t)); - if (!trap_PC_ReadToken( handle, &token )) { + if (!trap_Parse_ReadToken( handle, &token )) { break; } @@ -996,7 +996,7 @@ void UI_ParseMenu(const char *menuFile) { Menu_New(handle); } } - trap_PC_FreeSource(handle); + trap_Parse_FreeSource(handle); } /* @@ -1038,14 +1038,14 @@ qboolean UI_LoadInfoPane( int handle ) { memset( &token, 0, sizeof( pc_token_t ) ); - if( !trap_PC_ReadToken( handle, &token ) ) + if( !trap_Parse_ReadToken( handle, &token ) ) break; if( !Q_stricmp( token.string, "name" ) ) { memset( &token, 0, sizeof( pc_token_t ) ); - if( !trap_PC_ReadToken( handle, &token ) ) + if( !trap_Parse_ReadToken( handle, &token ) ) break; uiInfo.tremInfoPanes[ uiInfo.tremInfoPaneCount ].name = String_Alloc( token.string ); @@ -1057,7 +1057,7 @@ qboolean UI_LoadInfoPane( int handle ) memset( &token, 0, sizeof( pc_token_t ) ); - if( !trap_PC_ReadToken( handle, &token ) ) + if( !trap_Parse_ReadToken( handle, &token ) ) break; graphic = &uiInfo.tremInfoPanes[ uiInfo.tremInfoPaneCount ].numGraphics; @@ -1075,7 +1075,7 @@ qboolean UI_LoadInfoPane( int handle ) memset( &token, 0, sizeof( pc_token_t ) ); - if( !trap_PC_ReadToken( handle, &token ) ) + if( !trap_Parse_ReadToken( handle, &token ) ) break; if( !Q_stricmp( token.string, "center" ) ) @@ -1085,7 +1085,7 @@ qboolean UI_LoadInfoPane( int handle ) memset( &token, 0, sizeof( pc_token_t ) ); - if( !trap_PC_ReadToken( handle, &token ) ) + if( !trap_Parse_ReadToken( handle, &token ) ) break; uiInfo.tremInfoPanes[ uiInfo.tremInfoPaneCount ].graphics[ *graphic ].graphic = @@ -1093,14 +1093,14 @@ qboolean UI_LoadInfoPane( int handle ) memset( &token, 0, sizeof( pc_token_t ) ); - if( !trap_PC_ReadToken( handle, &token ) ) + if( !trap_Parse_ReadToken( handle, &token ) ) break; uiInfo.tremInfoPanes[ uiInfo.tremInfoPaneCount ].graphics[ *graphic ].width = token.intvalue; memset( &token, 0, sizeof( pc_token_t ) ); - if( !trap_PC_ReadToken( handle, &token ) ) + if( !trap_Parse_ReadToken( handle, &token ) ) break; uiInfo.tremInfoPanes[ uiInfo.tremInfoPaneCount ].graphics[ *graphic ].height = token.intvalue; @@ -1115,7 +1115,7 @@ qboolean UI_LoadInfoPane( int handle ) { memset( &token, 0, sizeof( pc_token_t ) ); - if( !trap_PC_ReadToken( handle, &token ) ) + if( !trap_Parse_ReadToken( handle, &token ) ) break; Q_strcat( uiInfo.tremInfoPanes[ uiInfo.tremInfoPaneCount ].text, MAX_INFOPANE_TEXT, token.string ); @@ -1124,7 +1124,7 @@ qboolean UI_LoadInfoPane( int handle ) { memset( &token, 0, sizeof( pc_token_t ) ); - if( !trap_PC_ReadToken( handle, &token ) ) + if( !trap_Parse_ReadToken( handle, &token ) ) break; if( !Q_stricmp( token.string, "left" ) ) @@ -1167,7 +1167,7 @@ void UI_LoadInfoPanes( const char *file ) uiInfo.tremInfoPaneCount = count = 0; - handle = trap_PC_LoadSource( file ); + handle = trap_Parse_LoadSource( file ); if( !handle ) { @@ -1177,7 +1177,7 @@ void UI_LoadInfoPanes( const char *file ) while( 1 ) { - if( !trap_PC_ReadToken( handle, &token ) ) + if( !trap_Parse_ReadToken( handle, &token ) ) break; if( token.string[ 0 ] == 0 ) @@ -1193,13 +1193,13 @@ void UI_LoadInfoPanes( const char *file ) } } - trap_PC_FreeSource( handle ); + trap_Parse_FreeSource( handle ); } qboolean Load_Menu(int handle) { pc_token_t token; - if (!trap_PC_ReadToken(handle, &token)) + if (!trap_Parse_ReadToken(handle, &token)) return qfalse; if (token.string[0] != '{') { return qfalse; @@ -1207,7 +1207,7 @@ qboolean Load_Menu(int handle) { while ( 1 ) { - if (!trap_PC_ReadToken(handle, &token)) + if (!trap_Parse_ReadToken(handle, &token)) return qfalse; if ( token.string[0] == 0 ) { @@ -1230,10 +1230,10 @@ void UI_LoadMenus(const char *menuFile, qboolean reset) { start = trap_Milliseconds(); - handle = trap_PC_LoadSource( menuFile ); + handle = trap_Parse_LoadSource( menuFile ); if (!handle) { trap_Error( va( S_COLOR_YELLOW "menu file not found: %s, using default\n", menuFile ) ); - handle = trap_PC_LoadSource( "ui/menus.txt" ); + handle = trap_Parse_LoadSource( "ui/menus.txt" ); if (!handle) { trap_Error( va( S_COLOR_RED "default menu file not found: ui/menus.txt, unable to continue!\n", menuFile ) ); } @@ -1246,7 +1246,7 @@ void UI_LoadMenus(const char *menuFile, qboolean reset) { } while ( 1 ) { - if (!trap_PC_ReadToken(handle, &token)) + if (!trap_Parse_ReadToken(handle, &token)) break; if( token.string[0] == 0 || token.string[0] == '}') { break; @@ -1267,7 +1267,7 @@ void UI_LoadMenus(const char *menuFile, qboolean reset) { Com_Printf("UI menu load time = %d milli seconds\n", trap_Milliseconds() - start); - trap_PC_FreeSource( handle ); + trap_Parse_FreeSource( handle ); } void UI_Load( void ) { diff --git a/src/ui/ui_public.h b/src/ui/ui_public.h index 9e39d52b..3f26a8ba 100644 --- a/src/ui/ui_public.h +++ b/src/ui/ui_public.h @@ -91,11 +91,6 @@ typedef enum { UI_MEMORY_REMAINING, UI_R_REGISTERFONT, UI_R_MODELBOUNDS, - UI_PC_ADD_GLOBAL_DEFINE, - UI_PC_LOAD_SOURCE, - UI_PC_FREE_SOURCE, - UI_PC_READ_TOKEN, - UI_PC_SOURCE_FILE_AND_LINE, UI_S_STOPBACKGROUNDTRACK, UI_S_STARTBACKGROUNDTRACK, UI_REAL_TIME, @@ -123,6 +118,12 @@ typedef enum { UI_FS_SEEK, UI_SET_PBCLSTATUS, + UI_PARSE_ADD_GLOBAL_DEFINE, + UI_PARSE_LOAD_SOURCE, + UI_PARSE_FREE_SOURCE, + UI_PARSE_READ_TOKEN, + UI_PARSE_SOURCE_FILE_AND_LINE, + UI_MEMSET = 100, UI_MEMCPY, UI_STRNCPY, diff --git a/src/ui/ui_shared.c b/src/ui/ui_shared.c index d5001b10..041ea7ec 100644 --- a/src/ui/ui_shared.c +++ b/src/ui/ui_shared.c @@ -271,7 +271,7 @@ void PC_SourceWarning(int handle, char *format, ...) { filename[0] = '\0'; line = 0; - trap_PC_SourceFileAndLine(handle, filename, &line); + trap_Parse_SourceFileAndLine(handle, filename, &line); Com_Printf(S_COLOR_YELLOW "WARNING: %s, line %d: %s\n", filename, line, string); } @@ -293,7 +293,7 @@ void PC_SourceError(int handle, char *format, ...) { filename[0] = '\0'; line = 0; - trap_PC_SourceFileAndLine(handle, filename, &line); + trap_Parse_SourceFileAndLine(handle, filename, &line); Com_Printf(S_COLOR_RED "ERROR: %s, line %d: %s\n", filename, line, string); } @@ -343,10 +343,10 @@ qboolean PC_Float_Parse(int handle, float *f) { pc_token_t token; int negative = qfalse; - if (!trap_PC_ReadToken(handle, &token)) + if (!trap_Parse_ReadToken(handle, &token)) return qfalse; if (token.string[0] == '-') { - if (!trap_PC_ReadToken(handle, &token)) + if (!trap_Parse_ReadToken(handle, &token)) return qfalse; negative = qtrue; } @@ -423,10 +423,10 @@ qboolean PC_Int_Parse(int handle, int *i) { pc_token_t token; int negative = qfalse; - if (!trap_PC_ReadToken(handle, &token)) + if (!trap_Parse_ReadToken(handle, &token)) return qfalse; if (token.string[0] == '-') { - if (!trap_PC_ReadToken(handle, &token)) + if (!trap_Parse_ReadToken(handle, &token)) return qfalse; negative = qtrue; } @@ -500,7 +500,7 @@ PC_String_Parse qboolean PC_String_Parse(int handle, const char **out) { pc_token_t token; - if (!trap_PC_ReadToken(handle, &token)) + if (!trap_Parse_ReadToken(handle, &token)) return qfalse; *(out) = String_Alloc(token.string); @@ -520,14 +520,14 @@ qboolean PC_Script_Parse(int handle, const char **out) { // scripts start with { and have ; separated command lists.. commands are command, arg.. // basically we want everything between the { } as it will be interpreted at run time - if (!trap_PC_ReadToken(handle, &token)) + if (!trap_Parse_ReadToken(handle, &token)) return qfalse; if (Q_stricmp(token.string, "{") != 0) { return qfalse; } while ( 1 ) { - if (!trap_PC_ReadToken(handle, &token)) + if (!trap_Parse_ReadToken(handle, &token)) return qfalse; if (Q_stricmp(token.string, "}") == 0) { @@ -5225,7 +5225,7 @@ qboolean ItemParse_cvarStrList( itemDef_t *item, int handle ) { multiPtr->count = 0; multiPtr->strDef = qtrue; - if (!trap_PC_ReadToken(handle, &token)) + if (!trap_Parse_ReadToken(handle, &token)) return qfalse; if (*token.string != '{') { return qfalse; @@ -5233,7 +5233,7 @@ qboolean ItemParse_cvarStrList( itemDef_t *item, int handle ) { pass = 0; while ( 1 ) { - if (!trap_PC_ReadToken(handle, &token)) { + if (!trap_Parse_ReadToken(handle, &token)) { PC_SourceError(handle, "end of file inside menu item\n"); return qfalse; } @@ -5273,14 +5273,14 @@ qboolean ItemParse_cvarFloatList( itemDef_t *item, int handle ) { multiPtr->count = 0; multiPtr->strDef = qfalse; - if (!trap_PC_ReadToken(handle, &token)) + if (!trap_Parse_ReadToken(handle, &token)) return qfalse; if (*token.string != '{') { return qfalse; } while ( 1 ) { - if (!trap_PC_ReadToken(handle, &token)) { + if (!trap_Parse_ReadToken(handle, &token)) { PC_SourceError(handle, "end of file inside menu item\n"); return qfalse; } @@ -5459,13 +5459,13 @@ qboolean Item_Parse(int handle, itemDef_t *item) { keywordHash_t *key; - if (!trap_PC_ReadToken(handle, &token)) + if (!trap_Parse_ReadToken(handle, &token)) return qfalse; if (*token.string != '{') { return qfalse; } while ( 1 ) { - if (!trap_PC_ReadToken(handle, &token)) { + if (!trap_Parse_ReadToken(handle, &token)) { PC_SourceError(handle, "end of file inside menu item\n"); return qfalse; } @@ -5860,7 +5860,7 @@ qboolean Menu_Parse(int handle, menuDef_t *menu) { pc_token_t token; keywordHash_t *key; - if (!trap_PC_ReadToken(handle, &token)) + if (!trap_Parse_ReadToken(handle, &token)) return qfalse; if (*token.string != '{') { return qfalse; @@ -5869,7 +5869,7 @@ qboolean Menu_Parse(int handle, menuDef_t *menu) { while ( 1 ) { memset(&token, 0, sizeof(pc_token_t)); - if (!trap_PC_ReadToken(handle, &token)) { + if (!trap_Parse_ReadToken(handle, &token)) { PC_SourceError(handle, "end of file inside menu\n"); return qfalse; } diff --git a/src/ui/ui_shared.h b/src/ui/ui_shared.h index 09de834e..202cda52 100644 --- a/src/ui/ui_shared.h +++ b/src/ui/ui_shared.h @@ -442,11 +442,11 @@ void Controls_SetDefaults( void ); //for cg_draw.c void Item_Text_AutoWrapped_Paint( itemDef_t *item ); -int trap_PC_AddGlobalDefine( char *define ); -int trap_PC_LoadSource( const char *filename ); -int trap_PC_FreeSource( int handle ); -int trap_PC_ReadToken( int handle, pc_token_t *pc_token ); -int trap_PC_SourceFileAndLine( int handle, char *filename, int *line ); +int trap_Parse_AddGlobalDefine( char *define ); +int trap_Parse_LoadSource( const char *filename ); +int trap_Parse_FreeSource( int handle ); +int trap_Parse_ReadToken( int handle, pc_token_t *pc_token ); +int trap_Parse_SourceFileAndLine( int handle, char *filename, int *line ); void BindingFromName( const char *cvar ); extern char g_nameBind1[ 32 ]; diff --git a/src/ui/ui_syscalls.asm b/src/ui/ui_syscalls.asm index fa30bf70..fb37c736 100644 --- a/src/ui/ui_syscalls.asm +++ b/src/ui/ui_syscalls.asm @@ -55,37 +55,37 @@ equ trap_Cvar_Update -52 equ trap_MemoryRemaining -53 equ trap_R_RegisterFont -54 equ trap_R_ModelBounds -55 -equ trap_PC_AddGlobalDefine -56 -equ trap_PC_LoadSource -57 -equ trap_PC_FreeSource -58 -equ trap_PC_ReadToken -59 -equ trap_PC_SourceFileAndLine -60 -equ trap_S_StopBackgroundTrack -61 -equ trap_S_StartBackgroundTrack -62 -equ trap_RealTime -63 -equ trap_LAN_GetServerCount -64 -equ trap_LAN_GetServerAddressString -65 -equ trap_LAN_GetServerInfo -66 -equ trap_LAN_MarkServerVisible -67 -equ trap_LAN_UpdateVisiblePings -68 -equ trap_LAN_ResetPings -69 -equ trap_LAN_LoadCachedServers -70 -equ trap_LAN_SaveCachedServers -71 -equ trap_LAN_AddServer -72 -equ trap_LAN_RemoveServer -73 -equ trap_CIN_PlayCinematic -74 -equ trap_CIN_StopCinematic -75 -equ trap_CIN_RunCinematic -76 -equ trap_CIN_DrawCinematic -77 -equ trap_CIN_SetExtents -78 -equ trap_R_RemapShader -79 -equ trap_LAN_ServerStatus -80 -equ trap_LAN_GetServerPing -81 -equ trap_LAN_ServerIsVisible -82 -equ trap_LAN_CompareServers -83 -equ trap_FS_Seek -84 -equ trap_SetPbClStatus -85 +equ trap_S_StopBackgroundTrack -56 +equ trap_S_StartBackgroundTrack -57 +equ trap_RealTime -58 +equ trap_LAN_GetServerCount -59 +equ trap_LAN_GetServerAddressString -60 +equ trap_LAN_GetServerInfo -61 +equ trap_LAN_MarkServerVisible -62 +equ trap_LAN_UpdateVisiblePings -63 +equ trap_LAN_ResetPings -64 +equ trap_LAN_LoadCachedServers -65 +equ trap_LAN_SaveCachedServers -66 +equ trap_LAN_AddServer -67 +equ trap_LAN_RemoveServer -68 +equ trap_CIN_PlayCinematic -69 +equ trap_CIN_StopCinematic -70 +equ trap_CIN_RunCinematic -71 +equ trap_CIN_DrawCinematic -72 +equ trap_CIN_SetExtents -73 +equ trap_R_RemapShader -74 +equ trap_LAN_ServerStatus -75 +equ trap_LAN_GetServerPing -76 +equ trap_LAN_ServerIsVisible -77 +equ trap_LAN_CompareServers -78 +equ trap_FS_Seek -79 +equ trap_SetPbClStatus -80 +equ trap_Parse_AddGlobalDefine -81 +equ trap_Parse_LoadSource -82 +equ trap_Parse_FreeSource -83 +equ trap_Parse_ReadToken -84 +equ trap_Parse_SourceFileAndLine -85 equ memset -101 diff --git a/src/ui/ui_syscalls.c b/src/ui/ui_syscalls.c index 545bcecc..528658e4 100644 --- a/src/ui/ui_syscalls.c +++ b/src/ui/ui_syscalls.c @@ -316,24 +316,24 @@ int trap_MemoryRemaining( void ) { return syscall( UI_MEMORY_REMAINING ); } -int trap_PC_AddGlobalDefine( char *define ) { - return syscall( UI_PC_ADD_GLOBAL_DEFINE, define ); +int trap_Parse_AddGlobalDefine( char *define ) { + return syscall( UI_PARSE_ADD_GLOBAL_DEFINE, define ); } -int trap_PC_LoadSource( const char *filename ) { - return syscall( UI_PC_LOAD_SOURCE, filename ); +int trap_Parse_LoadSource( const char *filename ) { + return syscall( UI_PARSE_LOAD_SOURCE, filename ); } -int trap_PC_FreeSource( int handle ) { - return syscall( UI_PC_FREE_SOURCE, handle ); +int trap_Parse_FreeSource( int handle ) { + return syscall( UI_PARSE_FREE_SOURCE, handle ); } -int trap_PC_ReadToken( int handle, pc_token_t *pc_token ) { - return syscall( UI_PC_READ_TOKEN, handle, pc_token ); +int trap_Parse_ReadToken( int handle, pc_token_t *pc_token ) { + return syscall( UI_PARSE_READ_TOKEN, handle, pc_token ); } -int trap_PC_SourceFileAndLine( int handle, char *filename, int *line ) { - return syscall( UI_PC_SOURCE_FILE_AND_LINE, handle, filename, line ); +int trap_Parse_SourceFileAndLine( int handle, char *filename, int *line ) { + return syscall( UI_PARSE_SOURCE_FILE_AND_LINE, handle, filename, line ); } void trap_S_StopBackgroundTrack( void ) { |