1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822 |
- /*
- ===========================================================================
- Copyright (C) 1999-2005 Id Software, Inc.
- This file is part of Quake III Arena source code.
- Quake III Arena source code 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.
- Quake III Arena source code 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 Foobar; 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 "../game/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 "../game/botlib.h"
- #include "../game/be_aas.h"
- #include "be_aas_funcs.h"
- #include "be_interface.h"
- #include "be_ai_weight.h"
- #include "../game/be_ai_goal.h"
- #include "../game/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},
- {0, 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
|