mirror of
https://github.com/yquake2/yquake2remaster.git
synced 2025-03-22 02:42:11 +00:00
jabot: add checkges from 0.9.3 version
This commit is contained in:
parent
ec60ebd7f8
commit
04e7a303db
20 changed files with 551 additions and 557 deletions
|
@ -103,6 +103,8 @@ Games:
|
|||
* Dawn of Darkness:
|
||||
* Docs: <https://www.moddb.com/mods/dawn-of-darkness1/downloads/dod-mood-scripts-gsm-tutorials-fgd-and-def-file>
|
||||
* Demo: [Episode 1](https://www.moddb.com/mods/dawn-of-darkness1/downloads/dawn-of-darkness-episode-1)
|
||||
* JaBot:
|
||||
* SDK: <https://www.moddb.com/mods/jabotq2/downloads/jabot-q2-v09x-win32-and-linux>
|
||||
* Additional maps used for check maps support:
|
||||
* PSX: <https://www.moddb.com/mods/quake-ii-psx/downloads/quake-ii-psx-10>
|
||||
* ReRelease N64 Jam: <https://www.moddb.com/games/quake-2/addons/quake-2-re-release-n64-sp-map-jam>
|
||||
|
@ -176,7 +178,6 @@ Goals, fully finished goals could be checked in [here](CHANGELOG):
|
|||
* [ ] Support scalled textures for models and walls in soft render and fix
|
||||
lighting with remastered maps,
|
||||
* [ ] Modified ReRelease game code support with removed KEX only related code.
|
||||
* [ ] Add support for [JaBot](https://www.moddb.com/mods/jabotq2/downloads/jabot-q2-v09x-win32-and-linux)
|
||||
|
||||
Not a goal:
|
||||
|
||||
|
|
|
@ -42,16 +42,14 @@ static gitem_t *blueflag;
|
|||
//==========================================
|
||||
void BOT_DMclass_Move(edict_t *self, usercmd_t *ucmd)
|
||||
{
|
||||
// int current_node_flags = 0;
|
||||
int next_node_flags = 0;
|
||||
int current_link_type = 0;
|
||||
int i;
|
||||
|
||||
// current_node_flags = nodes[self->ai.current_node].flags;
|
||||
next_node_flags = nodes[self->ai.next_node].flags;
|
||||
if( AI_PlinkExists( self->ai.current_node, self->ai.next_node ))
|
||||
next_node_flags = nodes[self->ai->next_node].flags;
|
||||
if( AI_PlinkExists( self->ai->current_node, self->ai->next_node ))
|
||||
{
|
||||
current_link_type = AI_PlinkMoveType( self->ai.current_node, self->ai.next_node );
|
||||
current_link_type = AI_PlinkMoveType( self->ai->current_node, self->ai->next_node );
|
||||
//Com_Printf("%s\n", AI_LinkString( current_link_type ));
|
||||
}
|
||||
|
||||
|
@ -59,8 +57,8 @@ void BOT_DMclass_Move(edict_t *self, usercmd_t *ucmd)
|
|||
if( current_link_type == LINK_PLATFORM )
|
||||
{
|
||||
// Move to the center
|
||||
self->ai.move_vector[2] = 0; // kill z movement
|
||||
if(VectorLength(self->ai.move_vector) > 10)
|
||||
self->ai->move_vector[2] = 0; // kill z movement
|
||||
if(VectorLength(self->ai->move_vector) > 10)
|
||||
ucmd->forwardmove = 200; // walk to center
|
||||
|
||||
AI_ChangeAngle(self);
|
||||
|
@ -71,7 +69,7 @@ void BOT_DMclass_Move(edict_t *self, usercmd_t *ucmd)
|
|||
{
|
||||
// is lift down?
|
||||
for(i=0;i<nav.num_ents;i++){
|
||||
if( nav.ents[i].node == self->ai.next_node )
|
||||
if( nav.ents[i].node == self->ai->next_node )
|
||||
{
|
||||
//testing line
|
||||
//vec3_t tPoint;
|
||||
|
@ -83,15 +81,16 @@ void BOT_DMclass_Move(edict_t *self, usercmd_t *ucmd)
|
|||
//AITools_DrawLine( self->s.origin, tPoint );
|
||||
|
||||
//if not reachable, wait for it (only height matters)
|
||||
if( (nav.ents[i].ent->s.origin[2] + nav.ents[i].ent->maxs[2])
|
||||
> (self->s.origin[2] + self->mins[2] + AI_JUMPABLE_HEIGHT) )
|
||||
if( ((nav.ents[i].ent->s.origin[2] + nav.ents[i].ent->maxs[2])
|
||||
> (self->s.origin[2] + self->mins[2] + AI_JUMPABLE_HEIGHT) ) &&
|
||||
nav.ents[i].ent->moveinfo.state != STATE_BOTTOM) //jabot092(2)
|
||||
return; //wait for elevator
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ladder movement
|
||||
if( self->ai.is_ladder )
|
||||
if( self->is_ladder )
|
||||
{
|
||||
ucmd->forwardmove = 70;
|
||||
ucmd->upmove = 200;
|
||||
|
@ -100,17 +99,17 @@ void BOT_DMclass_Move(edict_t *self, usercmd_t *ucmd)
|
|||
}
|
||||
|
||||
// Falling off ledge
|
||||
if(!self->groundentity && !self->ai.is_step && !self->ai.is_swim )
|
||||
if(!self->groundentity && !self->is_step && !self->is_swim )
|
||||
{
|
||||
AI_ChangeAngle(self);
|
||||
if (current_link_type == LINK_JUMPPAD ) {
|
||||
ucmd->forwardmove = 100;
|
||||
} else if( current_link_type == LINK_JUMP ) {
|
||||
self->velocity[0] = self->ai.move_vector[0] * 280;
|
||||
self->velocity[1] = self->ai.move_vector[1] * 280;
|
||||
self->velocity[0] = self->ai->move_vector[0] * 280;
|
||||
self->velocity[1] = self->ai->move_vector[1] * 280;
|
||||
} else {
|
||||
self->velocity[0] = self->ai.move_vector[0] * 160;
|
||||
self->velocity[1] = self->ai.move_vector[1] * 160;
|
||||
self->velocity[0] = self->ai->move_vector[0] * 160;
|
||||
self->velocity[1] = self->ai->move_vector[1] * 160;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -122,7 +121,7 @@ void BOT_DMclass_Move(edict_t *self, usercmd_t *ucmd)
|
|||
vec3_t v1, v2;
|
||||
//check floor in front, if there's none... Jump!
|
||||
VectorCopy( self->s.origin, v1 );
|
||||
VectorCopy( self->ai.move_vector, v2 );
|
||||
VectorCopy( self->ai->move_vector, v2 );
|
||||
VectorNormalize( v2 );
|
||||
VectorMA( v1, 12, v2, v1 );
|
||||
v1[2] += self->mins[2];
|
||||
|
@ -148,12 +147,12 @@ void BOT_DMclass_Move(edict_t *self, usercmd_t *ucmd)
|
|||
return;
|
||||
|
||||
// swimming
|
||||
if( self->ai.is_swim )
|
||||
if( self->is_swim )
|
||||
{
|
||||
// We need to be pointed up/down
|
||||
AI_ChangeAngle(self);
|
||||
|
||||
if( !(gi.pointcontents(nodes[self->ai.next_node].origin) & MASK_WATER) ) // Exit water
|
||||
if( !(gi.pointcontents(nodes[self->ai->next_node].origin) & MASK_WATER) ) // Exit water
|
||||
ucmd->upmove = 400;
|
||||
|
||||
ucmd->forwardmove = 300;
|
||||
|
@ -193,7 +192,7 @@ void BOT_DMclass_Wander(edict_t *self, usercmd_t *ucmd)
|
|||
vec3_t temp;
|
||||
|
||||
// Do not move
|
||||
if(self->ai.next_move_time > level.time)
|
||||
if(self->ai->next_move_time > level.time)
|
||||
return;
|
||||
|
||||
if (self->deadflag)
|
||||
|
@ -208,7 +207,7 @@ void BOT_DMclass_Wander(edict_t *self, usercmd_t *ucmd)
|
|||
self->velocity[0] = 0;
|
||||
self->velocity[1] = 0;
|
||||
self->velocity[2] = 0;
|
||||
self->ai.next_move_time = level.time + 0.5;
|
||||
self->ai->next_move_time = level.time + 0.5;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -261,7 +260,7 @@ void BOT_DMclass_Wander(edict_t *self, usercmd_t *ucmd)
|
|||
|
||||
self->s.angles[YAW] += random() * 180 - 90;
|
||||
|
||||
if (!self->ai.is_step)// if there is ground continue otherwise wait for next move
|
||||
if (!self->is_step)// if there is ground continue otherwise wait for next move
|
||||
ucmd->forwardmove = 0; //0
|
||||
else if( AI_CanMove( self, BOT_MOVE_FORWARD))
|
||||
ucmd->forwardmove = 100;
|
||||
|
@ -365,35 +364,35 @@ qboolean BOT_DMclass_FindEnemy(edict_t *self)
|
|||
return true;
|
||||
|
||||
// Find Enemy
|
||||
for(i=0;i<num_players;i++)
|
||||
for(i=0;i<num_AIEnemies;i++)
|
||||
{
|
||||
if(players[i] == NULL || players[i] == self
|
||||
|| players[i]->solid == SOLID_NOT)
|
||||
if( AIEnemies[i] == NULL || AIEnemies[i] == self
|
||||
|| AIEnemies[i]->solid == SOLID_NOT)
|
||||
continue;
|
||||
|
||||
//Ignore players with 0 weight (was set at botstatus)
|
||||
if(self->ai.status.playersWeights[i] == 0)
|
||||
if(self->ai->status.playersWeights[i] == 0)
|
||||
continue;
|
||||
|
||||
if(!players[i]->deadflag && visible(self, players[i]) &&
|
||||
if( !AIEnemies[i]->deadflag && visible(self, AIEnemies[i]) &&
|
||||
//trap_inPVS (self->s.origin, players[i]->s.origin))
|
||||
gi.inPVS(self->s.origin, players[i]->s.origin))
|
||||
gi.inPVS(self->s.origin, AIEnemies[i]->s.origin))
|
||||
{
|
||||
//(weight enemies from fusionbot) Is enemy visible, or is it too close to ignore
|
||||
VectorSubtract(self->s.origin, players[i]->s.origin, dist);
|
||||
VectorSubtract(self->s.origin, AIEnemies[i]->s.origin, dist);
|
||||
weight = VectorLength( dist );
|
||||
|
||||
//modify weight based on precomputed player weights
|
||||
weight *= (1.0 - self->ai.status.playersWeights[i]);
|
||||
weight *= (1.0 - self->ai->status.playersWeights[i]);
|
||||
|
||||
if( infront( self, players[i] ) ||
|
||||
if( infront( self, AIEnemies[i] ) ||
|
||||
(weight < 300 ) )
|
||||
{
|
||||
// Check if best target, or better than current target
|
||||
if (weight < bestweight)
|
||||
{
|
||||
bestweight = weight;
|
||||
bestenemy = players[i];
|
||||
bestenemy = AIEnemies[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -402,10 +401,10 @@ qboolean BOT_DMclass_FindEnemy(edict_t *self)
|
|||
// If best enemy, set up
|
||||
if(bestenemy)
|
||||
{
|
||||
// if (AIDevel.debugChased && bot_showcombat->value && bestenemy->ai.is_bot)
|
||||
// gi.cprintf(NULL, PRINT_HIGH, "%s: selected %s as enemy.\n",
|
||||
// self->ai.pers.netname,
|
||||
// bestenemy->ai.pers.netname);
|
||||
// if (AIDevel.debugChased && bot_showcombat->value && bestenemy->ai->is_bot)
|
||||
// gi.cprintf(AIDevel.chaseguy, PRINT_HIGH, "%s: selected %s as enemy.\n",
|
||||
// self->ai->pers.netname,
|
||||
// bestenemy->ai->pers.netname);
|
||||
|
||||
self->enemy = bestenemy;
|
||||
return true;
|
||||
|
@ -442,7 +441,7 @@ qboolean BOT_DMClass_ChangeWeapon (edict_t *ent, gitem_t *item)
|
|||
|
||||
// Change to this weapon
|
||||
ent->client->newweapon = item;
|
||||
ent->ai.changeweapon_timeout = level.time + 6.0;
|
||||
ent->ai->changeweapon_timeout = level.time + 6.0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -465,7 +464,7 @@ void BOT_DMclass_ChooseWeapon(edict_t *self)
|
|||
if(!self->enemy)
|
||||
return;
|
||||
|
||||
if( self->ai.changeweapon_timeout > level.time )
|
||||
if( self->ai->changeweapon_timeout > level.time )
|
||||
return;
|
||||
|
||||
// Base weapon selection on distance:
|
||||
|
@ -572,22 +571,22 @@ void BOT_DMclass_FireWeapon (edict_t *self, usercmd_t *ucmd)
|
|||
}
|
||||
|
||||
// modify attack angles based on accuracy (mess this up to make the bot's aim not so deadly)
|
||||
target[0] += (random()-0.5) * ((MAX_BOT_SKILL - self->ai.pers.skillLevel) *2);
|
||||
target[1] += (random()-0.5) * ((MAX_BOT_SKILL - self->ai.pers.skillLevel) *2);
|
||||
target[0] += (random()-0.5) * ((MAX_BOT_SKILL - self->ai->pers.skillLevel) *2);
|
||||
target[1] += (random()-0.5) * ((MAX_BOT_SKILL - self->ai->pers.skillLevel) *2);
|
||||
|
||||
// Set direction
|
||||
VectorSubtract (target, self->s.origin, self->ai.move_vector);
|
||||
vectoangles (self->ai.move_vector, angles);
|
||||
VectorSubtract (target, self->s.origin, self->ai->move_vector);
|
||||
vectoangles (self->ai->move_vector, angles);
|
||||
VectorCopy(angles,self->s.angles);
|
||||
|
||||
|
||||
// Set the attack
|
||||
firedelay = random()*(MAX_BOT_SKILL*1.8);
|
||||
if (firedelay > (MAX_BOT_SKILL - self->ai.pers.skillLevel) && BOT_DMclass_CheckShot(self, target))
|
||||
if (firedelay > (MAX_BOT_SKILL - self->ai->pers.skillLevel) && BOT_DMclass_CheckShot(self, target))
|
||||
ucmd->buttons = BUTTON_ATTACK;
|
||||
|
||||
//if(AIDevel.debugChased && bot_showcombat->integer)
|
||||
// gi.cprintf(NULL, PRINT_HIGH, "%s: attacking %s\n",self->bot.pers.netname ,self->enemy->r.client->pers.netname);
|
||||
// gi.cprintf(AIDevel.devguy, PRINT_HIGH, "%s: attacking %s\n",self->bot.pers.netname ,self->enemy->r.client->pers.netname);
|
||||
}
|
||||
|
||||
|
||||
|
@ -600,48 +599,48 @@ void BOT_DMclass_WeightPlayers(edict_t *self)
|
|||
int i;
|
||||
|
||||
//clear
|
||||
memset(self->ai.status.playersWeights, 0, sizeof (self->ai.status.playersWeights));
|
||||
memset(self->ai->status.playersWeights, 0, sizeof (self->ai->status.playersWeights));
|
||||
|
||||
for( i=0; i<num_players; i++ )
|
||||
for( i=0; i<num_AIEnemies; i++ )
|
||||
{
|
||||
if( players[i] == NULL )
|
||||
if( AIEnemies[i] == NULL )
|
||||
continue;
|
||||
|
||||
if( players[i] == self )
|
||||
if( AIEnemies[i] == self )
|
||||
continue;
|
||||
|
||||
//ignore spectators and dead players
|
||||
if( players[i]->svflags & SVF_NOCLIENT || players[i]->deadflag ) {
|
||||
self->ai.status.playersWeights[i] = 0.0f;
|
||||
if( AIEnemies[i]->svflags & SVF_NOCLIENT || AIEnemies[i]->deadflag ) {
|
||||
self->ai->status.playersWeights[i] = 0.0f;
|
||||
continue;
|
||||
}
|
||||
|
||||
if( ctf->value )
|
||||
{
|
||||
if( players[i]->client->resp.ctf_team != self->client->resp.ctf_team )
|
||||
if( AIEnemies[i]->client->resp.ctf_team != self->client->resp.ctf_team )
|
||||
{
|
||||
//being at enemy team gives a small weight, but weight afterall
|
||||
self->ai.status.playersWeights[i] = 0.2;
|
||||
self->ai->status.playersWeights[i] = 0.2;
|
||||
|
||||
//enemy has redflag
|
||||
if( redflag && players[i]->client->pers.inventory[ITEM_INDEX(redflag)]
|
||||
if( redflag && AIEnemies[i]->client->pers.inventory[ITEM_INDEX(redflag)]
|
||||
&& (self->client->resp.ctf_team == CTF_TEAM1) )
|
||||
{
|
||||
if( !self->client->pers.inventory[ITEM_INDEX(blueflag)] ) //don't hunt if you have the other flag, let others do
|
||||
self->ai.status.playersWeights[i] = 0.9;
|
||||
self->ai->status.playersWeights[i] = 0.9;
|
||||
}
|
||||
|
||||
//enemy has blueflag
|
||||
if( blueflag && players[i]->client->pers.inventory[ITEM_INDEX(blueflag)]
|
||||
if( blueflag && AIEnemies[i]->client->pers.inventory[ITEM_INDEX(blueflag)]
|
||||
&& (self->client->resp.ctf_team == CTF_TEAM2) )
|
||||
{
|
||||
if( !self->client->pers.inventory[ITEM_INDEX(redflag)] ) //don't hunt if you have the other flag, let others do
|
||||
self->ai.status.playersWeights[i] = 0.9;
|
||||
self->ai->status.playersWeights[i] = 0.9;
|
||||
}
|
||||
}
|
||||
}
|
||||
else //if not at ctf every player has some value
|
||||
self->ai.status.playersWeights[i] = 0.3;
|
||||
self->ai->status.playersWeights[i] = 0.3;
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -703,7 +702,7 @@ void BOT_DMclass_WeightInventory(edict_t *self)
|
|||
client = self->client;
|
||||
|
||||
//reset with persistant values
|
||||
memcpy(self->ai.status.inventoryWeights, self->ai.pers.inventoryWeights, sizeof(self->ai.pers.inventoryWeights));
|
||||
memcpy(self->ai->status.inventoryWeights, self->ai->pers.inventoryWeights, sizeof(self->ai->pers.inventoryWeights));
|
||||
|
||||
|
||||
//weight ammo down if bot doesn't have the weapon for it,
|
||||
|
@ -713,57 +712,57 @@ void BOT_DMclass_WeightInventory(edict_t *self)
|
|||
//AMMO_BULLETS
|
||||
|
||||
if (!AI_CanPick_Ammo (self, AIWeapons[WEAP_MACHINEGUN].ammoItem) )
|
||||
self->ai.status.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_MACHINEGUN].ammoItem)] = 0.0;
|
||||
self->ai->status.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_MACHINEGUN].ammoItem)] = 0.0;
|
||||
//find out if it has a weapon for this amno
|
||||
else if (!client->pers.inventory[ITEM_INDEX(AIWeapons[WEAP_CHAINGUN].weaponItem)]
|
||||
&& !client->pers.inventory[ITEM_INDEX(AIWeapons[WEAP_MACHINEGUN].weaponItem)] )
|
||||
self->ai.status.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_MACHINEGUN].ammoItem)] *= LowNeedFactor;
|
||||
self->ai->status.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_MACHINEGUN].ammoItem)] *= LowNeedFactor;
|
||||
|
||||
//AMMO_SHELLS:
|
||||
|
||||
//find out if it's packed up
|
||||
if (!AI_CanPick_Ammo (self, AIWeapons[WEAP_SHOTGUN].ammoItem) )
|
||||
self->ai.status.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_SHOTGUN].ammoItem)] = 0.0;
|
||||
self->ai->status.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_SHOTGUN].ammoItem)] = 0.0;
|
||||
//find out if it has a weapon for this amno
|
||||
else if (!client->pers.inventory[ITEM_INDEX(AIWeapons[WEAP_SHOTGUN].weaponItem)]
|
||||
&& !client->pers.inventory[ITEM_INDEX(AIWeapons[WEAP_SUPERSHOTGUN].weaponItem)] )
|
||||
self->ai.status.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_SHOTGUN].ammoItem)] *= LowNeedFactor;
|
||||
self->ai->status.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_SHOTGUN].ammoItem)] *= LowNeedFactor;
|
||||
|
||||
//AMMO_ROCKETS:
|
||||
|
||||
//find out if it's packed up
|
||||
if (!AI_CanPick_Ammo (self, AIWeapons[WEAP_ROCKETLAUNCHER].ammoItem))
|
||||
self->ai.status.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_ROCKETLAUNCHER].ammoItem)] = 0.0;
|
||||
self->ai->status.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_ROCKETLAUNCHER].ammoItem)] = 0.0;
|
||||
//find out if it has a weapon for this amno
|
||||
else if (!client->pers.inventory[ITEM_INDEX(AIWeapons[WEAP_ROCKETLAUNCHER].weaponItem)] )
|
||||
self->ai.status.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_ROCKETLAUNCHER].ammoItem)] *= LowNeedFactor;
|
||||
self->ai->status.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_ROCKETLAUNCHER].ammoItem)] *= LowNeedFactor;
|
||||
|
||||
//AMMO_GRENADES:
|
||||
|
||||
//find if it's packed up
|
||||
if (!AI_CanPick_Ammo (self, AIWeapons[WEAP_GRENADES].ammoItem))
|
||||
self->ai.status.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_GRENADES].ammoItem)] = 0.0;
|
||||
self->ai->status.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_GRENADES].ammoItem)] = 0.0;
|
||||
//grenades are also weapons, and are weighted down by LowNeedFactor in weapons group
|
||||
|
||||
//AMMO_CELLS:
|
||||
|
||||
//find out if it's packed up
|
||||
if (!AI_CanPick_Ammo (self, AIWeapons[WEAP_HYPERBLASTER].ammoItem))
|
||||
self->ai.status.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_HYPERBLASTER].ammoItem)] = 0.0;
|
||||
self->ai->status.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_HYPERBLASTER].ammoItem)] = 0.0;
|
||||
//find out if it has a weapon for this amno
|
||||
else if (!client->pers.inventory[ITEM_INDEX(AIWeapons[WEAP_HYPERBLASTER].weaponItem)]
|
||||
&& !client->pers.inventory[ITEM_INDEX(AIWeapons[WEAP_BFG].weaponItem)]
|
||||
&& !client->pers.inventory[ITEM_INDEX(FindItemByClassname("item_power_shield"))])
|
||||
self->ai.status.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_HYPERBLASTER].ammoItem)] *= LowNeedFactor;
|
||||
self->ai->status.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_HYPERBLASTER].ammoItem)] *= LowNeedFactor;
|
||||
|
||||
//AMMO_SLUGS:
|
||||
|
||||
//find out if it's packed up
|
||||
if (!AI_CanPick_Ammo (self, AIWeapons[WEAP_RAILGUN].ammoItem))
|
||||
self->ai.status.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_RAILGUN].ammoItem)] = 0.0;
|
||||
self->ai->status.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_RAILGUN].ammoItem)] = 0.0;
|
||||
//find out if it has a weapon for this amno
|
||||
else if (!client->pers.inventory[ITEM_INDEX(AIWeapons[WEAP_RAILGUN].weaponItem)] )
|
||||
self->ai.status.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_RAILGUN].ammoItem)] *= LowNeedFactor;
|
||||
self->ai->status.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_RAILGUN].ammoItem)] *= LowNeedFactor;
|
||||
|
||||
|
||||
//WEAPONS
|
||||
|
@ -772,23 +771,23 @@ void BOT_DMclass_WeightInventory(edict_t *self)
|
|||
//weight weapon down if bot already has it
|
||||
for (i=0; i<WEAP_TOTAL; i++) {
|
||||
if ( AIWeapons[i].weaponItem && client->pers.inventory[ITEM_INDEX(AIWeapons[i].weaponItem)])
|
||||
self->ai.status.inventoryWeights[ITEM_INDEX(AIWeapons[i].weaponItem)] *= LowNeedFactor;
|
||||
self->ai->status.inventoryWeights[ITEM_INDEX(AIWeapons[i].weaponItem)] *= LowNeedFactor;
|
||||
}
|
||||
|
||||
//ARMOR
|
||||
//-----------------------------------------------------
|
||||
//shards are ALWAYS accepted but still...
|
||||
if (!AI_CanUseArmor ( FindItemByClassname("item_armor_shard"), self ))
|
||||
self->ai.status.inventoryWeights[ITEM_INDEX(FindItemByClassname("item_armor_shard"))] = 0.0;
|
||||
self->ai->status.inventoryWeights[ITEM_INDEX(FindItemByClassname("item_armor_shard"))] = 0.0;
|
||||
|
||||
if (!AI_CanUseArmor ( FindItemByClassname("item_armor_jacket"), self ))
|
||||
self->ai.status.inventoryWeights[ITEM_INDEX(FindItemByClassname("item_armor_jacket"))] = 0.0;
|
||||
self->ai->status.inventoryWeights[ITEM_INDEX(FindItemByClassname("item_armor_jacket"))] = 0.0;
|
||||
|
||||
if (!AI_CanUseArmor ( FindItemByClassname("item_armor_combat"), self ))
|
||||
self->ai.status.inventoryWeights[ITEM_INDEX(FindItemByClassname("item_armor_combat"))] = 0.0;
|
||||
self->ai->status.inventoryWeights[ITEM_INDEX(FindItemByClassname("item_armor_combat"))] = 0.0;
|
||||
|
||||
if (!AI_CanUseArmor ( FindItemByClassname("item_armor_body"), self ))
|
||||
self->ai.status.inventoryWeights[ITEM_INDEX(FindItemByClassname("item_armor_body"))] = 0.0;
|
||||
self->ai->status.inventoryWeights[ITEM_INDEX(FindItemByClassname("item_armor_body"))] = 0.0;
|
||||
|
||||
|
||||
//TECH :
|
||||
|
@ -798,10 +797,10 @@ void BOT_DMclass_WeightInventory(edict_t *self)
|
|||
|| self->client->pers.inventory[ITEM_INDEX( FindItemByClassname("item_tech3"))]
|
||||
|| self->client->pers.inventory[ITEM_INDEX( FindItemByClassname("item_tech4"))] )
|
||||
{
|
||||
self->ai.status.inventoryWeights[ITEM_INDEX( FindItemByClassname("item_tech1"))] = 0.0;
|
||||
self->ai.status.inventoryWeights[ITEM_INDEX( FindItemByClassname("item_tech2"))] = 0.0;
|
||||
self->ai.status.inventoryWeights[ITEM_INDEX( FindItemByClassname("item_tech3"))] = 0.0;
|
||||
self->ai.status.inventoryWeights[ITEM_INDEX( FindItemByClassname("item_tech4"))] = 0.0;
|
||||
self->ai->status.inventoryWeights[ITEM_INDEX( FindItemByClassname("item_tech1"))] = 0.0;
|
||||
self->ai->status.inventoryWeights[ITEM_INDEX( FindItemByClassname("item_tech2"))] = 0.0;
|
||||
self->ai->status.inventoryWeights[ITEM_INDEX( FindItemByClassname("item_tech3"))] = 0.0;
|
||||
self->ai->status.inventoryWeights[ITEM_INDEX( FindItemByClassname("item_tech4"))] = 0.0;
|
||||
}
|
||||
|
||||
//CTF:
|
||||
|
@ -814,16 +813,16 @@ void BOT_DMclass_WeightInventory(edict_t *self)
|
|||
|
||||
//flags have weights defined inside persistant inventory. Remove weight from the unwanted one/s.
|
||||
if (blueflag && blueflag != wantedFlag)
|
||||
self->ai.status.inventoryWeights[ITEM_INDEX(blueflag)] = 0.0;
|
||||
else if (redflag && redflag != wantedFlag)
|
||||
self->ai.status.inventoryWeights[ITEM_INDEX(redflag)] = 0.0;
|
||||
self->ai->status.inventoryWeights[ITEM_INDEX(blueflag)] = 0.0;
|
||||
if (redflag && redflag != wantedFlag)
|
||||
self->ai->status.inventoryWeights[ITEM_INDEX(redflag)] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================
|
||||
// BOT_DMclass_UpdateStatus
|
||||
// update ai.status values based on bot state,
|
||||
// update ai->status values based on bot state,
|
||||
// so ai can decide based on these settings
|
||||
//==========================================
|
||||
void BOT_DMclass_UpdateStatus( edict_t *self )
|
||||
|
@ -838,14 +837,14 @@ void BOT_DMclass_UpdateStatus( edict_t *self )
|
|||
//JALFIXMEQ2
|
||||
/*
|
||||
if (self->client->jumppad_time)
|
||||
self->ai.status.jumpadReached = true; //jumpad time from client to botStatus
|
||||
self->ai->status.jumpadReached = true; //jumpad time from client to botStatus
|
||||
else
|
||||
self->ai.status.jumpadReached = false;
|
||||
self->ai->status.jumpadReached = false;
|
||||
*/
|
||||
if (self->client->ps.pmove.pm_flags & PMF_TIME_TELEPORT)
|
||||
self->ai.status.TeleportReached = true;
|
||||
self->ai->status.TeleportReached = true;
|
||||
else
|
||||
self->ai.status.TeleportReached = false;
|
||||
self->ai->status.TeleportReached = false;
|
||||
|
||||
//set up AI status for the upcoming AI_frame
|
||||
BOT_DMclass_WeightInventory( self ); //weight items
|
||||
|
@ -860,7 +859,7 @@ void BOT_DMclass_UpdateStatus( edict_t *self )
|
|||
void BOT_DMClass_BloquedTimeout( edict_t *self )
|
||||
{
|
||||
self->health = 0;
|
||||
self->ai.bloqued_timeout = level.time + 15.0;
|
||||
self->ai->bloqued_timeout = level.time + 15.0;
|
||||
self->die(self, self, self, 100000, vec3_origin);
|
||||
self->nextthink = level.time + FRAMETIME;
|
||||
}
|
||||
|
@ -896,24 +895,24 @@ void BOT_DMclass_RunFrame( edict_t *self )
|
|||
{
|
||||
BOT_DMclass_ChooseWeapon( self );
|
||||
BOT_DMclass_FireWeapon( self, &ucmd );
|
||||
self->ai.state = BOT_STATE_ATTACK;
|
||||
self->ai.state_combat_timeout = level.time + 1.0;
|
||||
self->ai->state = BOT_STATE_ATTACK;
|
||||
self->ai->state_combat_timeout = level.time + 1.0;
|
||||
|
||||
} else if( self->ai.state == BOT_STATE_ATTACK &&
|
||||
level.time > self->ai.state_combat_timeout)
|
||||
} else if( self->ai->state == BOT_STATE_ATTACK &&
|
||||
level.time > self->ai->state_combat_timeout)
|
||||
{
|
||||
//Jalfixme: change to: AI_SetUpStateMove(self);
|
||||
self->ai.state = BOT_STATE_MOVE;
|
||||
self->ai->state = BOT_STATE_MOVE;
|
||||
}
|
||||
|
||||
// Execute the move, or wander
|
||||
if( self->ai.state == BOT_STATE_MOVE )
|
||||
if( self->ai->state == BOT_STATE_MOVE )
|
||||
BOT_DMclass_Move( self, &ucmd );
|
||||
|
||||
else if(self->ai.state == BOT_STATE_ATTACK)
|
||||
else if(self->ai->state == BOT_STATE_ATTACK)
|
||||
BOT_DMclass_CombatMovement( self, &ucmd );
|
||||
|
||||
else if ( self->ai.state == BOT_STATE_WANDER )
|
||||
else if ( self->ai->state == BOT_STATE_WANDER )
|
||||
BOT_DMclass_Wander( self, &ucmd );
|
||||
|
||||
|
||||
|
@ -943,61 +942,61 @@ void BOT_DMclass_InitPersistant(edict_t *self)
|
|||
|
||||
//copy name
|
||||
if (self->client->pers.netname[0])
|
||||
self->ai.pers.netname = self->client->pers.netname;
|
||||
self->ai->pers.netname = self->client->pers.netname;
|
||||
else
|
||||
self->ai.pers.netname = "dmBot";
|
||||
self->ai->pers.netname = "dmBot";
|
||||
|
||||
//set 'class' functions
|
||||
self->ai.pers.RunFrame = BOT_DMclass_RunFrame;
|
||||
self->ai.pers.UpdateStatus = BOT_DMclass_UpdateStatus;
|
||||
self->ai.pers.bloquedTimeout = BOT_DMClass_BloquedTimeout;
|
||||
self->ai.pers.deadFrame = BOT_DMclass_DeadFrame;
|
||||
self->ai->pers.RunFrame = BOT_DMclass_RunFrame;
|
||||
self->ai->pers.UpdateStatus = BOT_DMclass_UpdateStatus;
|
||||
self->ai->pers.bloquedTimeout = BOT_DMClass_BloquedTimeout;
|
||||
self->ai->pers.deadFrame = BOT_DMclass_DeadFrame;
|
||||
|
||||
//available moveTypes for this class
|
||||
self->ai.pers.moveTypesMask = (LINK_MOVE|LINK_STAIRS|LINK_FALL|LINK_WATER|LINK_WATERJUMP|LINK_JUMPPAD|LINK_PLATFORM|LINK_TELEPORT|LINK_LADDER|LINK_JUMP|LINK_CROUCH);
|
||||
self->ai->pers.moveTypesMask = (LINK_MOVE|LINK_STAIRS|LINK_FALL|LINK_WATER|LINK_WATERJUMP|LINK_JUMPPAD|LINK_PLATFORM|LINK_TELEPORT|LINK_LADDER|LINK_JUMP|LINK_CROUCH);
|
||||
|
||||
//Persistant Inventory Weights (0 = can not pick)
|
||||
memset(self->ai.pers.inventoryWeights, 0, sizeof (self->ai.pers.inventoryWeights));
|
||||
memset(self->ai->pers.inventoryWeights, 0, sizeof (self->ai->pers.inventoryWeights));
|
||||
|
||||
//weapons
|
||||
self->ai.pers.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_BLASTER].weaponItem)] = 0.0;
|
||||
self->ai->pers.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_BLASTER].weaponItem)] = 0.0;
|
||||
//self->bot.pers.inventoryWeights[ITEM_INDEX(FindItemByClassname("weapon_blaster"))] = 0.0; //it's the same thing
|
||||
self->ai.pers.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_SHOTGUN].weaponItem)] = 0.5;
|
||||
self->ai.pers.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_SUPERSHOTGUN].weaponItem)] = 0.7;
|
||||
self->ai.pers.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_MACHINEGUN].weaponItem)] = 0.5;
|
||||
self->ai.pers.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_CHAINGUN].weaponItem)] = 0.7;
|
||||
self->ai.pers.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_GRENADES].weaponItem)] = 0.5;
|
||||
self->ai.pers.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_GRENADELAUNCHER].weaponItem)] = 0.6;
|
||||
self->ai.pers.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_ROCKETLAUNCHER].weaponItem)] = 0.8;
|
||||
self->ai.pers.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_HYPERBLASTER].weaponItem)] = 0.7;
|
||||
self->ai.pers.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_RAILGUN].weaponItem)] = 0.8;
|
||||
self->ai.pers.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_BFG].weaponItem)] = 0.5;
|
||||
self->ai->pers.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_SHOTGUN].weaponItem)] = 0.5;
|
||||
self->ai->pers.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_SUPERSHOTGUN].weaponItem)] = 0.7;
|
||||
self->ai->pers.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_MACHINEGUN].weaponItem)] = 0.5;
|
||||
self->ai->pers.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_CHAINGUN].weaponItem)] = 0.7;
|
||||
self->ai->pers.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_GRENADES].weaponItem)] = 0.5;
|
||||
self->ai->pers.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_GRENADELAUNCHER].weaponItem)] = 0.6;
|
||||
self->ai->pers.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_ROCKETLAUNCHER].weaponItem)] = 0.8;
|
||||
self->ai->pers.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_HYPERBLASTER].weaponItem)] = 0.7;
|
||||
self->ai->pers.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_RAILGUN].weaponItem)] = 0.8;
|
||||
self->ai->pers.inventoryWeights[ITEM_INDEX(AIWeapons[WEAP_BFG].weaponItem)] = 0.5;
|
||||
|
||||
//ammo
|
||||
self->ai.pers.inventoryWeights[ITEM_INDEX(FindItemByClassname("ammo_shells"))] = 0.5;
|
||||
self->ai.pers.inventoryWeights[ITEM_INDEX(FindItemByClassname("ammo_bullets"))] = 0.5;
|
||||
self->ai.pers.inventoryWeights[ITEM_INDEX(FindItemByClassname("ammo_cells"))] = 0.5;
|
||||
self->ai.pers.inventoryWeights[ITEM_INDEX(FindItemByClassname("ammo_rockets"))] = 0.5;
|
||||
self->ai.pers.inventoryWeights[ITEM_INDEX(FindItemByClassname("ammo_slugs"))] = 0.5;
|
||||
self->ai.pers.inventoryWeights[ITEM_INDEX(FindItemByClassname("ammo_grenades"))] = 0.5;
|
||||
self->ai->pers.inventoryWeights[ITEM_INDEX(FindItemByClassname("ammo_shells"))] = 0.5;
|
||||
self->ai->pers.inventoryWeights[ITEM_INDEX(FindItemByClassname("ammo_bullets"))] = 0.5;
|
||||
self->ai->pers.inventoryWeights[ITEM_INDEX(FindItemByClassname("ammo_cells"))] = 0.5;
|
||||
self->ai->pers.inventoryWeights[ITEM_INDEX(FindItemByClassname("ammo_rockets"))] = 0.5;
|
||||
self->ai->pers.inventoryWeights[ITEM_INDEX(FindItemByClassname("ammo_slugs"))] = 0.5;
|
||||
self->ai->pers.inventoryWeights[ITEM_INDEX(FindItemByClassname("ammo_grenades"))] = 0.5;
|
||||
|
||||
//armor
|
||||
self->ai.pers.inventoryWeights[ITEM_INDEX(FindItemByClassname("item_armor_body"))] = 0.9;
|
||||
self->ai.pers.inventoryWeights[ITEM_INDEX(FindItemByClassname("item_armor_combat"))] = 0.8;
|
||||
self->ai.pers.inventoryWeights[ITEM_INDEX(FindItemByClassname("item_armor_jacket"))] = 0.5;
|
||||
self->ai.pers.inventoryWeights[ITEM_INDEX(FindItemByClassname("item_armor_shard"))] = 0.2;
|
||||
self->ai->pers.inventoryWeights[ITEM_INDEX(FindItemByClassname("item_armor_body"))] = 0.9;
|
||||
self->ai->pers.inventoryWeights[ITEM_INDEX(FindItemByClassname("item_armor_combat"))] = 0.8;
|
||||
self->ai->pers.inventoryWeights[ITEM_INDEX(FindItemByClassname("item_armor_jacket"))] = 0.5;
|
||||
self->ai->pers.inventoryWeights[ITEM_INDEX(FindItemByClassname("item_armor_shard"))] = 0.2;
|
||||
|
||||
//techs
|
||||
self->ai.pers.inventoryWeights[ITEM_INDEX(FindItemByClassname("item_tech1"))] = 0.5;
|
||||
self->ai.pers.inventoryWeights[ITEM_INDEX(FindItemByClassname("item_tech2"))] = 0.5;
|
||||
self->ai.pers.inventoryWeights[ITEM_INDEX(FindItemByClassname("item_tech3"))] = 0.5;
|
||||
self->ai.pers.inventoryWeights[ITEM_INDEX(FindItemByClassname("item_tech4"))] = 0.5;
|
||||
self->ai->pers.inventoryWeights[ITEM_INDEX(FindItemByClassname("item_tech1"))] = 0.5;
|
||||
self->ai->pers.inventoryWeights[ITEM_INDEX(FindItemByClassname("item_tech2"))] = 0.5;
|
||||
self->ai->pers.inventoryWeights[ITEM_INDEX(FindItemByClassname("item_tech3"))] = 0.5;
|
||||
self->ai->pers.inventoryWeights[ITEM_INDEX(FindItemByClassname("item_tech4"))] = 0.5;
|
||||
|
||||
if( ctf->value ) {
|
||||
redflag = FindItemByClassname("item_flag_team1"); // store pointers to flags gitem_t, for
|
||||
blueflag = FindItemByClassname("item_flag_team2");// simpler comparisons inside this archive
|
||||
self->ai.pers.inventoryWeights[ITEM_INDEX(FindItemByClassname("item_flag_team1"))] = 3.0;
|
||||
self->ai.pers.inventoryWeights[ITEM_INDEX(FindItemByClassname("item_flag_team2"))] = 3.0;
|
||||
self->ai->pers.inventoryWeights[ITEM_INDEX(FindItemByClassname("item_flag_team1"))] = 3.0;
|
||||
self->ai->pers.inventoryWeights[ITEM_INDEX(FindItemByClassname("item_flag_team2"))] = 3.0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -47,42 +47,44 @@ void M_default_Move(edict_t *self, usercmd_t *ucmd)
|
|||
{
|
||||
// int current_node_flags = 0;
|
||||
// int next_node_flags = 0;
|
||||
// int current_node_flags = 0;
|
||||
// int next_node_flags = 0;
|
||||
int current_link_type = 0;
|
||||
// int i;
|
||||
|
||||
// current_node_flags = nodes[self->ai.current_node].flags;
|
||||
// next_node_flags = nodes[self->ai.next_node].flags;
|
||||
if( AI_PlinkExists( self->ai.current_node, self->ai.next_node ))
|
||||
// current_node_flags = nodes[self->ai->current_node].flags;
|
||||
// next_node_flags = nodes[self->ai->next_node].flags;
|
||||
if( AI_PlinkExists( self->ai->current_node, self->ai->next_node ))
|
||||
{
|
||||
current_link_type = AI_PlinkMoveType( self->ai.current_node, self->ai.next_node );
|
||||
current_link_type = AI_PlinkMoveType( self->ai->current_node, self->ai->next_node );
|
||||
//Com_Printf("%s\n", AI_LinkString( current_link_type ));
|
||||
}
|
||||
|
||||
// Falling off ledge
|
||||
if(!self->groundentity && !self->ai.is_step && !self->ai.is_swim )
|
||||
if(!self->groundentity && !self->is_step && !self->is_swim )
|
||||
{
|
||||
AI_ChangeAngle(self);
|
||||
if (current_link_type == LINK_JUMPPAD ) {
|
||||
ucmd->forwardmove = 100;
|
||||
} else if( current_link_type == LINK_JUMP ) {
|
||||
self->velocity[0] = self->ai.move_vector[0] * 280;
|
||||
self->velocity[1] = self->ai.move_vector[1] * 280;
|
||||
self->velocity[0] = self->ai->move_vector[0] * 280;
|
||||
self->velocity[1] = self->ai->move_vector[1] * 280;
|
||||
} else {
|
||||
self->velocity[0] = self->ai.move_vector[0] * 160;
|
||||
self->velocity[1] = self->ai.move_vector[1] * 160;
|
||||
self->velocity[0] = self->ai->move_vector[0] * 160;
|
||||
self->velocity[1] = self->ai->move_vector[1] * 160;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// swimming
|
||||
if( self->ai.is_swim )
|
||||
if( self->is_swim )
|
||||
{
|
||||
// We need to be pointed up/down
|
||||
AI_ChangeAngle(self);
|
||||
|
||||
//if( !(trap_PointContents(nodes[self->ai.next_node].origin) & MASK_WATER) ) // Exit water
|
||||
if( !(gi.pointcontents(nodes[self->ai.next_node].origin) & MASK_WATER) ) // Exit water
|
||||
//if( !(trap_PointContents(nodes[self->ai->next_node].origin) & MASK_WATER) ) // Exit water
|
||||
if( !(gi.pointcontents(nodes[self->ai->next_node].origin) & MASK_WATER) ) // Exit water
|
||||
ucmd->upmove = 400;
|
||||
|
||||
ucmd->forwardmove = 300;
|
||||
|
@ -234,18 +236,18 @@ void M_default_FireWeapon (edict_t *self)
|
|||
|
||||
|
||||
// modify attack angles based on accuracy (mess this up to make the bot's aim not so deadly)
|
||||
target[0] += (random()-0.5) * ((MAX_BOT_SKILL - self->ai.pers.skillLevel) *2);
|
||||
target[1] += (random()-0.5) * ((MAX_BOT_SKILL - self->ai.pers.skillLevel) *2);
|
||||
target[0] += (random()-0.5) * ((MAX_BOT_SKILL - self->ai->pers.skillLevel) *2);
|
||||
target[1] += (random()-0.5) * ((MAX_BOT_SKILL - self->ai->pers.skillLevel) *2);
|
||||
|
||||
// Set direction
|
||||
VectorSubtract (target, self->s.origin, self->ai.move_vector);
|
||||
vectoangles (self->ai.move_vector, angles);
|
||||
VectorSubtract (target, self->s.origin, self->ai->move_vector);
|
||||
vectoangles (self->ai->move_vector, angles);
|
||||
VectorCopy(angles,self->s.angles);
|
||||
|
||||
|
||||
// Set the attack
|
||||
firedelay = random()*(MAX_BOT_SKILL*1.8);
|
||||
if (firedelay > (MAX_BOT_SKILL - self->ai.pers.skillLevel) && M_default_CheckShot(self, target))
|
||||
if (firedelay > (MAX_BOT_SKILL - self->ai->pers.skillLevel) && M_default_CheckShot(self, target))
|
||||
{
|
||||
vec3_t start, forward, right;
|
||||
AngleVectors (self->s.angles, forward, right, NULL);
|
||||
|
@ -268,29 +270,29 @@ void M_default_WeightPlayers(edict_t *self)
|
|||
int i;
|
||||
|
||||
//clear
|
||||
memset(self->ai.status.playersWeights, 0, sizeof (self->ai.status.playersWeights));
|
||||
memset(self->ai->status.playersWeights, 0, sizeof (self->ai->status.playersWeights));
|
||||
|
||||
for(i=0;i<num_players;i++)
|
||||
for(i=0;i<num_AIEnemies;i++)
|
||||
{
|
||||
if (players[i] == NULL)
|
||||
if( AIEnemies[i] == NULL)
|
||||
continue;
|
||||
|
||||
if(players[i] == self)
|
||||
if( AIEnemies[i] == self)
|
||||
continue;
|
||||
|
||||
if( !strcmp(players[i]->classname, "monster") ) {
|
||||
self->ai.status.playersWeights[i] = 0.0f;
|
||||
if( !strcmp(AIEnemies[i]->classname, "monster") ) {
|
||||
self->ai->status.playersWeights[i] = 0.0f;
|
||||
continue;
|
||||
}
|
||||
|
||||
//ignore spectators and dead players
|
||||
if(players[i]->svflags & SVF_NOCLIENT || players[i]->deadflag) {
|
||||
self->ai.status.playersWeights[i] = 0.0f;
|
||||
if( AIEnemies[i]->svflags & SVF_NOCLIENT || AIEnemies[i]->deadflag) {
|
||||
self->ai->status.playersWeights[i] = 0.0f;
|
||||
continue;
|
||||
}
|
||||
|
||||
//every player has some value
|
||||
self->ai.status.playersWeights[i] = 0.3;
|
||||
self->ai->status.playersWeights[i] = 0.3;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -302,7 +304,7 @@ void M_default_WeightPlayers(edict_t *self)
|
|||
void M_default_WeightInventory(edict_t *self)
|
||||
{
|
||||
//reset with persistant values
|
||||
memcpy(self->ai.status.inventoryWeights, self->ai.pers.inventoryWeights, sizeof(self->ai.pers.inventoryWeights));
|
||||
memcpy(self->ai->status.inventoryWeights, self->ai->pers.inventoryWeights, sizeof(self->ai->pers.inventoryWeights));
|
||||
}
|
||||
|
||||
//==========================================
|
||||
|
@ -378,7 +380,7 @@ int M_default_GravityBoxStep( vec3_t origin, float scale, vec3_t movedir, vec3_t
|
|||
int movemask = 0;
|
||||
int eternalfall = 0;
|
||||
float /*xzdist,*/ xzscale;
|
||||
/* float ydist, yscale; */
|
||||
/*float ydist, yscale; */
|
||||
// float dist;
|
||||
|
||||
//trap_Trace( &trace, origin, mins, maxs, origin, passent, solidmask );
|
||||
|
@ -391,9 +393,8 @@ int M_default_GravityBoxStep( vec3_t origin, float scale, vec3_t movedir, vec3_t
|
|||
vectoangles( movedir, angles );
|
||||
|
||||
xzscale = scale;
|
||||
// yscale = scale;
|
||||
/*
|
||||
yscale = scale;
|
||||
|
||||
//remaining distance in planes
|
||||
if( scale < 1 )
|
||||
scale = 1;
|
||||
|
@ -593,10 +594,8 @@ qboolean M_default_movestep (edict_t *self, usercmd_t *ucmd)
|
|||
}
|
||||
|
||||
|
||||
qboolean M_walkmove (edict_t *ent, float yaw, float dist);
|
||||
//void G_SetPModelFrame (edict_t *ent);
|
||||
void M_WorldEffects (edict_t *ent);
|
||||
void M_droptofloor (edict_t *ent);
|
||||
|
||||
//==========================================
|
||||
// M_default_RunFrame
|
||||
//
|
||||
|
@ -612,30 +611,30 @@ void M_default_RunFrame( edict_t *self )
|
|||
{
|
||||
M_default_ChooseWeapon( self );
|
||||
M_default_FireWeapon( self );
|
||||
self->ai.state = BOT_STATE_ATTACK;
|
||||
self->ai.state_combat_timeout = level.time + 1.0;
|
||||
self->ai->state = BOT_STATE_ATTACK;
|
||||
self->ai->state_combat_timeout = level.time + 1.0;
|
||||
|
||||
} else if( self->ai.state == BOT_STATE_ATTACK &&
|
||||
level.time > self->ai.state_combat_timeout)
|
||||
} else if( self->ai->state == BOT_STATE_ATTACK &&
|
||||
level.time > self->ai->state_combat_timeout)
|
||||
{
|
||||
//Jalfixme: change to: AI_SetUpStateMove(self);
|
||||
self->ai.state = BOT_STATE_MOVE;
|
||||
self->ai->state = BOT_STATE_MOVE;
|
||||
}
|
||||
|
||||
// Execute the move, or wander
|
||||
if( self->ai.state == BOT_STATE_MOVE )
|
||||
if( self->ai->state == BOT_STATE_MOVE )
|
||||
M_default_Move( self, &ucmd );
|
||||
|
||||
else if(self->ai.state == BOT_STATE_ATTACK)
|
||||
else if(self->ai->state == BOT_STATE_ATTACK)
|
||||
M_default_CombatMovement( self, &ucmd );
|
||||
|
||||
else if ( self->ai.state == BOT_STATE_WANDER )
|
||||
else if ( self->ai->state == BOT_STATE_WANDER )
|
||||
M_default_Wander( self, &ucmd );
|
||||
|
||||
|
||||
//move a step
|
||||
if( M_default_movestep ( self, &ucmd ) )
|
||||
self->ai.bloqued_timeout = level.time + 10.0;
|
||||
self->ai->bloqued_timeout = level.time + 10.0;
|
||||
|
||||
M_WorldEffects (self);
|
||||
|
||||
|
|
|
@ -334,8 +334,8 @@ void AI_PathMap( void )
|
|||
int closest_node;
|
||||
|
||||
//DROP WATER JUMP NODE (not limited by delayed updates)
|
||||
if ( !player.ent->ai.is_swim && player.last_node != -1
|
||||
&& player.ent->ai.is_swim != player.ent->ai.was_swim)
|
||||
if ( !player.ent->is_swim && player.last_node != -1
|
||||
&& player.ent->is_swim != player.ent->was_swim)
|
||||
{
|
||||
AI_WaterJumpNode();
|
||||
last_update = level.time + NODE_UPDATE_DELAY; // slow down updates a bit
|
||||
|
@ -365,13 +365,13 @@ void AI_PathMap( void )
|
|||
return;
|
||||
|
||||
// Not on ground, and not in the water, so bail (deeper check by using a splitmodels function)
|
||||
if (!player.ent->ai.is_step )
|
||||
if (!player.ent->is_step )
|
||||
{
|
||||
if ( !player.ent->ai.is_swim ){
|
||||
if ( !player.ent->is_swim ){
|
||||
player.was_falling = true;
|
||||
return;
|
||||
}
|
||||
else if ( player.ent->ai.is_swim )
|
||||
else if ( player.ent->is_swim )
|
||||
player.was_falling = false;
|
||||
}
|
||||
|
||||
|
@ -415,7 +415,7 @@ void AI_PathMap( void )
|
|||
if( closest_node == INVALID )
|
||||
{
|
||||
// Add nodes in the water as needed
|
||||
if( player.ent->ai.is_swim )
|
||||
if( player.ent->is_swim )
|
||||
closest_node = AI_AddNode( player.ent->s.origin, (NODEFLAGS_WATER|NODEFLAGS_FLOAT) );
|
||||
else
|
||||
closest_node = AI_AddNode( player.ent->s.origin, 0 );
|
||||
|
|
|
@ -39,7 +39,8 @@
|
|||
//==========================================
|
||||
void AI_EnemyAdded(edict_t *ent)
|
||||
{
|
||||
players[num_players++] = ent;
|
||||
if( num_AIEnemies < MAX_EDICTS )
|
||||
AIEnemies[num_AIEnemies++] = ent;
|
||||
}
|
||||
|
||||
//==========================================
|
||||
|
@ -52,27 +53,26 @@ void AI_EnemyRemoved(edict_t *ent)
|
|||
int pos;
|
||||
|
||||
// watch for 0 players
|
||||
if(num_players == 0)
|
||||
if(num_AIEnemies < 1)
|
||||
return;
|
||||
|
||||
|
||||
// special case for only one player
|
||||
if(num_players == 1)
|
||||
if(num_AIEnemies == 1)
|
||||
{
|
||||
num_players = 0;
|
||||
num_AIEnemies = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the player
|
||||
for(i=0;i<num_players;i++)
|
||||
if(ent == players[i])
|
||||
for(i=0;i<num_AIEnemies;i++)
|
||||
if(ent == AIEnemies[i])
|
||||
pos = i;
|
||||
|
||||
// decrement
|
||||
for(i=pos;i<num_players-1;i++)
|
||||
players[i] = players[i+1];
|
||||
for( i=pos; i<num_AIEnemies-1; i++ )
|
||||
AIEnemies[i] = AIEnemies[i+1];
|
||||
|
||||
num_players--;
|
||||
num_AIEnemies--;
|
||||
}
|
||||
|
||||
|
||||
|
@ -211,25 +211,25 @@ float AI_ItemWeight(edict_t *self, edict_t *it)
|
|||
//IT_WEAPON
|
||||
if (it->item->flags & IT_WEAPON)
|
||||
{
|
||||
return self->ai.status.inventoryWeights[ITEM_INDEX(it->item)];
|
||||
return self->ai->status.inventoryWeights[ITEM_INDEX(it->item)];
|
||||
}
|
||||
|
||||
//IT_AMMO
|
||||
if (it->item->flags & IT_AMMO)
|
||||
{
|
||||
return self->ai.status.inventoryWeights[ITEM_INDEX(it->item)];
|
||||
return self->ai->status.inventoryWeights[ITEM_INDEX(it->item)];
|
||||
}
|
||||
|
||||
//IT_ARMOR
|
||||
if (it->item->flags & IT_ARMOR)
|
||||
{
|
||||
return self->ai.status.inventoryWeights[ITEM_INDEX(it->item)];
|
||||
return self->ai->status.inventoryWeights[ITEM_INDEX(it->item)];
|
||||
}
|
||||
|
||||
//IT_FLAG
|
||||
if (it->item->flags & IT_FLAG)
|
||||
{
|
||||
return self->ai.status.inventoryWeights[ITEM_INDEX(it->item)];
|
||||
return self->ai->status.inventoryWeights[ITEM_INDEX(it->item)];
|
||||
}
|
||||
|
||||
//IT_HEALTH
|
||||
|
@ -265,7 +265,7 @@ float AI_ItemWeight(edict_t *self, edict_t *it)
|
|||
//IT_TECH
|
||||
if (it->item->flags & IT_TECH)
|
||||
{
|
||||
return self->ai.status.inventoryWeights[ITEM_INDEX(it->item)];
|
||||
return self->ai->status.inventoryWeights[ITEM_INDEX(it->item)];
|
||||
}
|
||||
|
||||
//IT_STAY_COOP
|
||||
|
|
|
@ -407,7 +407,7 @@ int AI_GravityBoxStep( vec3_t origin, float scale, vec3_t destvec, vec3_t newori
|
|||
|
||||
droptofloor:
|
||||
|
||||
while(eternalfall < 20000000)
|
||||
while(eternalfall < 20000)
|
||||
{
|
||||
if( gi.pointcontents(neworigin) & MASK_WATER ) {
|
||||
|
||||
|
@ -443,8 +443,8 @@ droptofloor:
|
|||
eternalfall++;
|
||||
}
|
||||
|
||||
gi.error ("ETERNAL FALL\n");
|
||||
return 0;
|
||||
//gi.error ("ETERNAL FALL\n");
|
||||
return LINK_INVALID; //jabot092
|
||||
}
|
||||
|
||||
//==========================================
|
||||
|
|
|
@ -33,8 +33,6 @@
|
|||
|
||||
#include "ai_nodes_local.h"
|
||||
#include "ai_weapons.h"
|
||||
#include "astar.h"
|
||||
|
||||
|
||||
//bot debug_chase options
|
||||
// extern cvar_t *bot_showpath;
|
||||
|
@ -65,8 +63,8 @@ extern cvar_t *bot_debugmonster;
|
|||
|
||||
//acebot_items.c players table
|
||||
//----------------------------------------------------------
|
||||
extern int num_players;
|
||||
extern edict_t *players[MAX_CLIENTS]; // pointers to all players in the game
|
||||
extern int num_AIEnemies;
|
||||
extern edict_t *AIEnemies[MAX_EDICTS]; // pointers to all players in the game
|
||||
|
||||
|
||||
//Debug & creating and linking nodes
|
||||
|
@ -112,26 +110,27 @@ qboolean AI_ItemIsReachable(edict_t *self,vec3_t goal);
|
|||
// ai_movement.c
|
||||
//----------------------------------------------------------
|
||||
void AI_ChangeAngle (edict_t *ent);
|
||||
qboolean AI_MoveToGoalEntity(edict_t *self, usercmd_t *ucmd);
|
||||
qboolean AI_SpecialMove(edict_t *self, usercmd_t *ucmd);
|
||||
qboolean AI_CanMove(edict_t *self, int direction);
|
||||
qboolean AI_IsLadder(vec3_t origin, vec3_t v_angle, vec3_t mins, vec3_t maxs, edict_t *passent);
|
||||
qboolean AI_IsStep(edict_t *ent);
|
||||
qboolean AI_MoveToGoalEntity(edict_t *self, usercmd_t *ucmd);
|
||||
qboolean AI_SpecialMove(edict_t *self, usercmd_t *ucmd);
|
||||
qboolean AI_CanMove(edict_t *self, int direction);
|
||||
qboolean AI_IsLadder(vec3_t origin, vec3_t v_angle, vec3_t mins, vec3_t maxs, edict_t *passent);
|
||||
qboolean AI_IsStep (edict_t *ent);
|
||||
|
||||
// ai_navigation.c
|
||||
//----------------------------------------------------------
|
||||
int AI_FindCost(int from, int to, int movetypes);
|
||||
int AI_FindClosestReachableNode( vec3_t origin, edict_t *passent, int range, int flagsmask );
|
||||
void AI_SetGoal(edict_t *self, int goal_node);
|
||||
qboolean AI_FollowPath(edict_t *self);
|
||||
int AI_FindCost(int from, int to, int movetypes);
|
||||
int AI_FindClosestReachableNode( vec3_t origin, edict_t *passent, int range, int flagsmask );
|
||||
void AI_SetGoal(edict_t *self, int goal_node);
|
||||
qboolean AI_FollowPath(edict_t *self);
|
||||
|
||||
|
||||
// ai_nodes.c
|
||||
//----------------------------------------------------------
|
||||
qboolean AI_DropNodeOriginToFloor( vec3_t origin, edict_t *passent );
|
||||
void AI_InitNavigationData(void);
|
||||
int AI_FlagsForNode( vec3_t origin, edict_t *passent );
|
||||
float AI_Distance( vec3_t o1, vec3_t o2 );
|
||||
qboolean AI_DropNodeOriginToFloor( vec3_t origin, edict_t *passent );
|
||||
void AI_InitNavigationData(void);
|
||||
int AI_FlagsForNode( vec3_t origin, edict_t *passent );
|
||||
float AI_Distance( vec3_t o1, vec3_t o2 );
|
||||
|
||||
void AITools_AddBotRoamNode(void);
|
||||
|
||||
|
||||
|
@ -167,7 +166,7 @@ void AI_BotRoamFinishTimeouts(edict_t *self);
|
|||
//bot_classes
|
||||
//----------------------------------------------------------
|
||||
void BOT_DMclass_InitPersistant(edict_t *self);
|
||||
qboolean BOT_ChangeWeapon(edict_t *ent, gitem_t *item);
|
||||
qboolean BOT_ChangeWeapon (edict_t *ent, gitem_t *item);
|
||||
|
||||
//ai_weapons.c
|
||||
//----------------------------------------------------------
|
||||
|
|
|
@ -25,8 +25,8 @@
|
|||
#include "../header/local.h"
|
||||
#include "ai_local.h"
|
||||
|
||||
int num_players;
|
||||
edict_t *players[MAX_CLIENTS]; // pointers to all players in the game
|
||||
int num_AIEnemies;
|
||||
edict_t *AIEnemies[MAX_EDICTS]; // pointers to all players in the game
|
||||
ai_devel_t AIDevel;
|
||||
|
||||
// cvar_t *bot_showpath;
|
||||
|
@ -69,24 +69,48 @@ void AI_NewMap(void)
|
|||
AI_InitAIWeapons ();
|
||||
}
|
||||
|
||||
//==========================================
|
||||
// G_FreeAI
|
||||
// removes the AI handle from memory
|
||||
//==========================================
|
||||
void G_FreeAI( edict_t *ent )
|
||||
{
|
||||
if( !ent->ai ) return;
|
||||
|
||||
gi.TagFree (ent->ai);
|
||||
ent->ai = NULL;
|
||||
}
|
||||
|
||||
//==========================================
|
||||
// G_SpawnAI
|
||||
// allocate ai_handle_t for this entity
|
||||
//==========================================
|
||||
void G_SpawnAI( edict_t *ent )
|
||||
{
|
||||
if( !ent->ai )
|
||||
ent->ai = gi.TagMalloc (sizeof(ai_handle_t), TAG_LEVEL);
|
||||
|
||||
memset( ent->ai, 0, sizeof(ai_handle_t));
|
||||
}
|
||||
|
||||
//==========================================
|
||||
// AI_SetUpMoveWander
|
||||
//==========================================
|
||||
void AI_SetUpMoveWander( edict_t *ent )
|
||||
{
|
||||
ent->ai.state = BOT_STATE_WANDER;
|
||||
ent->ai.wander_timeout = level.time + 1.0;
|
||||
ent->ai.nearest_node_tries = 0;
|
||||
ent->ai->state = BOT_STATE_WANDER;
|
||||
ent->ai->wander_timeout = level.time + 1.0;
|
||||
ent->ai->nearest_node_tries = 0;
|
||||
|
||||
ent->ai.next_move_time = level.time;
|
||||
ent->ai.bloqued_timeout = level.time + 15.0;
|
||||
ent->ai->next_move_time = level.time;
|
||||
ent->ai->bloqued_timeout = level.time + 15.0;
|
||||
|
||||
ent->ai.goal_node = INVALID;
|
||||
ent->ai.current_node = INVALID;
|
||||
ent->ai.next_node = INVALID;
|
||||
ent->ai->goal_node = INVALID;
|
||||
ent->ai->current_node = INVALID;
|
||||
ent->ai->next_node = INVALID;
|
||||
}
|
||||
|
||||
|
||||
//==========================================
|
||||
// AI_ResetWeights
|
||||
// Init bot weights from bot-class weights.
|
||||
|
@ -94,8 +118,8 @@ void AI_SetUpMoveWander( edict_t *ent )
|
|||
void AI_ResetWeights(edict_t *ent)
|
||||
{
|
||||
//restore defaults from bot persistant
|
||||
memset(ent->ai.status.inventoryWeights, 0, sizeof (ent->ai.status.inventoryWeights));
|
||||
memcpy(ent->ai.status.inventoryWeights, ent->ai.pers.inventoryWeights, sizeof(ent->ai.pers.inventoryWeights));
|
||||
memset(ent->ai->status.inventoryWeights, 0, sizeof (ent->ai->status.inventoryWeights));
|
||||
memcpy(ent->ai->status.inventoryWeights, ent->ai->pers.inventoryWeights, sizeof(ent->ai->pers.inventoryWeights));
|
||||
}
|
||||
|
||||
|
||||
|
@ -109,24 +133,24 @@ void AI_ResetNavigation(edict_t *ent)
|
|||
|
||||
ent->enemy = NULL;
|
||||
ent->movetarget = NULL;
|
||||
ent->ai.state_combat_timeout = 0.0;
|
||||
ent->ai->state_combat_timeout = 0.0;
|
||||
|
||||
ent->ai.state = BOT_STATE_WANDER;
|
||||
ent->ai.wander_timeout = level.time;
|
||||
ent->ai.nearest_node_tries = 0;
|
||||
ent->ai->state = BOT_STATE_WANDER;
|
||||
ent->ai->wander_timeout = level.time;
|
||||
ent->ai->nearest_node_tries = 0;
|
||||
|
||||
ent->ai.next_move_time = level.time;
|
||||
ent->ai.bloqued_timeout = level.time + 15.0;
|
||||
ent->ai->next_move_time = level.time;
|
||||
ent->ai->bloqued_timeout = level.time + 15.0;
|
||||
|
||||
ent->ai.goal_node = INVALID;
|
||||
ent->ai.current_node = INVALID;
|
||||
ent->ai.next_node = INVALID;
|
||||
ent->ai->goal_node = INVALID;
|
||||
ent->ai->current_node = INVALID;
|
||||
ent->ai->next_node = INVALID;
|
||||
|
||||
VectorSet( ent->ai.move_vector, 0, 0, 0 );
|
||||
VectorSet( ent->ai->move_vector, 0, 0, 0 );
|
||||
|
||||
//reset bot_roams timeouts
|
||||
for( i=0; i<nav.num_broams; i++)
|
||||
ent->ai.status.broam_timeouts[i] = 0.0;
|
||||
ent->ai->status.broam_timeouts[i] = 0.0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -149,7 +173,7 @@ qboolean AI_BotRoamForLRGoal(edict_t *self, int current_node)
|
|||
|
||||
for( i=0; i<nav.num_broams; i++)
|
||||
{
|
||||
if( self->ai.status.broam_timeouts[i] > level.time)
|
||||
if( self->ai->status.broam_timeouts[i] > level.time)
|
||||
continue;
|
||||
|
||||
//limit cost finding by distance
|
||||
|
@ -158,7 +182,7 @@ qboolean AI_BotRoamForLRGoal(edict_t *self, int current_node)
|
|||
continue;
|
||||
|
||||
//find cost
|
||||
cost = AI_FindCost(current_node, nav.broams[i].node, self->ai.pers.moveTypesMask);
|
||||
cost = AI_FindCost(current_node, nav.broams[i].node, self->ai->pers.moveTypesMask);
|
||||
if(cost == INVALID || cost < 3) // ignore invalid and very short hops
|
||||
continue;
|
||||
|
||||
|
@ -177,11 +201,11 @@ qboolean AI_BotRoamForLRGoal(edict_t *self, int current_node)
|
|||
return false;
|
||||
|
||||
//set up the goal
|
||||
self->ai.state = BOT_STATE_MOVE;
|
||||
self->ai.tries = 0; // Reset the count of how many times we tried this goal
|
||||
self->ai->state = BOT_STATE_MOVE;
|
||||
self->ai->tries = 0; // Reset the count of how many times we tried this goal
|
||||
|
||||
// if(AIDevel.debugChased && bot_showlrgoal->value)
|
||||
// gi.cprintf(NULL, PRINT_HIGH, "%s: selected a bot roam of weight %f at node %d for LR goal.\n",self->ai.pers.netname, nav.broams[best_broam].weight, goal_node);
|
||||
// gi.cprintf(AIDevel.chaseguy, PRINT_HIGH, "%s: selected a bot roam of weight %f at node %d for LR goal.\n",self->ai->pers.netname, nav.broams[best_broam].weight, goal_node);
|
||||
|
||||
AI_SetGoal(self,goal_node);
|
||||
|
||||
|
@ -209,23 +233,22 @@ void AI_PickLongRangeGoal(edict_t *self)
|
|||
float dist;
|
||||
|
||||
// look for a target
|
||||
current_node = AI_FindClosestReachableNode(self->s.origin, self,((1+self->ai.nearest_node_tries)*NODE_DENSITY),NODE_ALL);
|
||||
self->ai.current_node = current_node;
|
||||
current_node = AI_FindClosestReachableNode(self->s.origin, self,((1+self->ai->nearest_node_tries)*NODE_DENSITY),NODE_ALL);
|
||||
self->ai->current_node = current_node;
|
||||
|
||||
if(current_node == -1) //failed. Go wandering :(
|
||||
{
|
||||
// if (AIDevel.debugChased && bot_showlrgoal->value)
|
||||
// gi.cprintf(NULL, PRINT_HIGH, "%s: LRGOAL: Closest node not found. Tries:%i\n", self->ai.pers.netname, self->ai.nearest_node_tries);
|
||||
// Com_Printf( "%s: LRGOAL: Closest node not found. Tries:%i\n", self->ai.pers.netname, self->ai.nearest_node_tries);
|
||||
// gi.cprintf(AIDevel.chaseguy, PRINT_HIGH, "%s: LRGOAL: Closest node not found. Tries:%i\n", self->ai->pers.netname, self->ai->nearest_node_tries);
|
||||
|
||||
if( self->ai.state != BOT_STATE_WANDER )
|
||||
if( self->ai->state != BOT_STATE_WANDER )
|
||||
AI_SetUpMoveWander( self );
|
||||
|
||||
self->ai.wander_timeout = level.time + 1.0;
|
||||
self->ai.nearest_node_tries++; //extend search radius with each try
|
||||
self->ai->wander_timeout = level.time + 1.0;
|
||||
self->ai->nearest_node_tries++; //extend search radius with each try
|
||||
return;
|
||||
}
|
||||
self->ai.nearest_node_tries = 0;
|
||||
self->ai->nearest_node_tries = 0;
|
||||
|
||||
|
||||
// Items
|
||||
|
@ -256,7 +279,7 @@ void AI_PickLongRangeGoal(edict_t *self)
|
|||
if( nav.items[i].ent->item->flags & (IT_WEAPON|IT_FLAG) && dist > 10000 )
|
||||
continue;
|
||||
|
||||
cost = AI_FindCost(current_node, nav.items[i].node, self->ai.pers.moveTypesMask);
|
||||
cost = AI_FindCost(current_node, nav.items[i].node, self->ai->pers.moveTypesMask);
|
||||
if(cost == INVALID || cost < 3) // ignore invalid and very short hops
|
||||
continue;
|
||||
|
||||
|
@ -273,24 +296,24 @@ void AI_PickLongRangeGoal(edict_t *self)
|
|||
|
||||
|
||||
// Players: This should be its own function and is for now just finds a player to set as the goal.
|
||||
for(i=0;i<num_players;i++)
|
||||
for( i=0; i<num_AIEnemies; i++ )
|
||||
{
|
||||
//ignore self & spectators
|
||||
if(players[i] == self || players[i]->svflags & SVF_NOCLIENT)
|
||||
if( AIEnemies[i] == self || AIEnemies[i]->svflags & SVF_NOCLIENT)
|
||||
continue;
|
||||
|
||||
//ignore zero weighted players
|
||||
if( self->ai.status.playersWeights[i] == 0.0f )
|
||||
if( self->ai->status.playersWeights[i] == 0.0f )
|
||||
continue;
|
||||
|
||||
node = AI_FindClosestReachableNode( players[i]->s.origin, players[i], NODE_DENSITY, NODE_ALL);
|
||||
cost = AI_FindCost(current_node, node, self->ai.pers.moveTypesMask);
|
||||
node = AI_FindClosestReachableNode( AIEnemies[i]->s.origin, AIEnemies[i], NODE_DENSITY, NODE_ALL);
|
||||
cost = AI_FindCost(current_node, node, self->ai->pers.moveTypesMask);
|
||||
|
||||
if(cost == INVALID || cost < 4) // ignore invalid and very short hops
|
||||
continue;
|
||||
|
||||
//precomputed player weights
|
||||
weight = self->ai.status.playersWeights[i];
|
||||
weight = self->ai->status.playersWeights[i];
|
||||
|
||||
//weight *= random(); // Allow random variations
|
||||
weight /= cost; // Check against cost of getting there
|
||||
|
@ -299,7 +322,7 @@ void AI_PickLongRangeGoal(edict_t *self)
|
|||
{
|
||||
best_weight = weight;
|
||||
goal_node = node;
|
||||
// goal_ent = players[i];
|
||||
// goal_ent = AIEnemies[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -309,24 +332,21 @@ void AI_PickLongRangeGoal(edict_t *self)
|
|||
//BOT_ROAMS
|
||||
if (!AI_BotRoamForLRGoal(self, current_node))
|
||||
{
|
||||
self->ai.goal_node = INVALID;
|
||||
self->ai.state = BOT_STATE_WANDER;
|
||||
self->ai.wander_timeout = level.time + 1.0;
|
||||
self->ai->goal_node = INVALID;
|
||||
self->ai->state = BOT_STATE_WANDER;
|
||||
self->ai->wander_timeout = level.time + 1.0;
|
||||
// if(AIDevel.debugChased && bot_showlrgoal->value)
|
||||
// gi.cprintf(NULL, PRINT_HIGH, "%s: did not find a LR goal, wandering.\n",self->ai.pers.netname);
|
||||
// Com_Printf( "%s: did not find a LR goal, wandering.\n",self->ai.pers.netname);
|
||||
// gi.cprintf(AIDevel.chaseguy, PRINT_HIGH, "%s: did not find a LR goal, wandering.\n",self->ai->pers.netname);
|
||||
}
|
||||
return; // no path?
|
||||
}
|
||||
|
||||
// OK, everything valid, let's start moving to our goal.
|
||||
self->ai.state = BOT_STATE_MOVE;
|
||||
self->ai.tries = 0; // Reset the count of how many times we tried this goal
|
||||
self->ai->state = BOT_STATE_MOVE;
|
||||
self->ai->tries = 0; // Reset the count of how many times we tried this goal
|
||||
|
||||
// if(goal_ent != NULL && AIDevel.debugChased && bot_showlrgoal->value)
|
||||
// gi.cprintf(NULL, PRINT_HIGH, "%s: selected a %s at node %d for LR goal.\n",self->ai.pers.netname, goal_ent->classname, goal_node);
|
||||
// if(goal_ent != NULL )
|
||||
// Com_Printf( "%s: selected a %s at node %d for LR goal.\n",self->ai.pers.netname, goal_ent->classname, goal_node);
|
||||
// gi.cprintf(AIDevel.chaseguy, PRINT_HIGH, "%s: selected a %s at node %d for LR goal.\n",self->ai->pers.netname, goal_ent->classname, goal_node);
|
||||
|
||||
AI_SetGoal(self,goal_node);
|
||||
}
|
||||
|
@ -359,10 +379,10 @@ void AI_PickShortRangeGoal(edict_t *self)
|
|||
if(strcmp(target->classname,"rocket")==0 || strcmp(target->classname,"grenade")==0)
|
||||
{
|
||||
//if player who shoot is a potential enemy
|
||||
if (self->ai.status.playersWeights[target->owner->s.number-1])
|
||||
if (self->ai->status.playersWeights[target->owner->s.number-1])
|
||||
{
|
||||
// if(AIDevel.debugChased && bot_showcombat->value)
|
||||
// gi.cprintf(NULL, PRINT_HIGH, "%s: ROCKET ALERT!\n", self->ai.pers.netname);
|
||||
// gi.cprintf(AIDevel.chaseguy, PRINT_HIGH, "%s: ROCKET ALERT!\n", self->ai->pers.netname);
|
||||
|
||||
self->enemy = target->owner; // set who fired the rocket as enemy
|
||||
return;
|
||||
|
@ -393,7 +413,7 @@ void AI_PickShortRangeGoal(edict_t *self)
|
|||
self->movetarget = best;
|
||||
self->goalentity = best;
|
||||
// if(AIDevel.debugChased && bot_showsrgoal->value && (self->goalentity != self->movetarget))
|
||||
// gi.cprintf(NULL, PRINT_HIGH, "%s: selected a %s for SR goal.\n",self->ai.pers.netname, self->movetarget->classname);
|
||||
// gi.cprintf(AIDevel.chaseguy, PRINT_HIGH, "%s: selected a %s for SR goal.\n",self->ai->pers.netname, self->movetarget->classname);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -406,20 +426,20 @@ void AI_CategorizePosition (edict_t *ent)
|
|||
{
|
||||
qboolean stepping = AI_IsStep(ent);
|
||||
|
||||
ent->ai.was_swim = ent->ai.is_swim;
|
||||
ent->ai.was_step = ent->ai.is_step;
|
||||
ent->was_swim = ent->is_swim;
|
||||
ent->was_step = ent->is_step;
|
||||
|
||||
ent->ai.is_ladder = AI_IsLadder( ent->s.origin, ent->s.angles, ent->mins, ent->maxs, ent );
|
||||
ent->is_ladder = AI_IsLadder( ent->s.origin, ent->s.angles, ent->mins, ent->maxs, ent );
|
||||
|
||||
M_CatagorizePosition(ent);
|
||||
if (ent->waterlevel > 2 || (ent->waterlevel && !stepping)) {
|
||||
ent->ai.is_swim = true;
|
||||
ent->ai.is_step = false;
|
||||
ent->is_swim = true;
|
||||
ent->is_step = false;
|
||||
return;
|
||||
}
|
||||
|
||||
ent->ai.is_swim = false;
|
||||
ent->ai.is_step = stepping;
|
||||
ent->is_swim = false;
|
||||
ent->is_step = stepping;
|
||||
}
|
||||
|
||||
|
||||
|
@ -429,46 +449,49 @@ void AI_CategorizePosition (edict_t *ent)
|
|||
//==========================================
|
||||
void AI_Think (edict_t *self)
|
||||
{
|
||||
if( !self->ai ) //jabot092(2)
|
||||
return;
|
||||
|
||||
AIDebug_SetChased(self); //jal:debug shit
|
||||
AI_CategorizePosition(self);
|
||||
|
||||
//freeze AI when dead
|
||||
if( self->deadflag ) {
|
||||
self->ai.pers.deadFrame(self);
|
||||
self->ai->pers.deadFrame(self);
|
||||
return;
|
||||
}
|
||||
|
||||
//if completely stuck somewhere
|
||||
if(VectorLength(self->velocity) > 37)
|
||||
self->ai.bloqued_timeout = level.time + 10.0;
|
||||
self->ai->bloqued_timeout = level.time + 10.0;
|
||||
|
||||
if( self->ai.bloqued_timeout < level.time ) {
|
||||
self->ai.pers.bloquedTimeout(self);
|
||||
if( self->ai->bloqued_timeout < level.time ) {
|
||||
self->ai->pers.bloquedTimeout(self);
|
||||
return;
|
||||
}
|
||||
|
||||
//update status information to feed up ai
|
||||
self->ai.pers.UpdateStatus(self);
|
||||
self->ai->pers.UpdateStatus(self);
|
||||
|
||||
//update position in path, set up move vector
|
||||
if( self->ai.state == BOT_STATE_MOVE ) {
|
||||
if( self->ai->state == BOT_STATE_MOVE ) {
|
||||
|
||||
if( !AI_FollowPath(self) )
|
||||
{
|
||||
AI_SetUpMoveWander( self );
|
||||
self->ai.wander_timeout = level.time - 1; //do it now
|
||||
self->ai->wander_timeout = level.time - 1; //do it now
|
||||
}
|
||||
}
|
||||
|
||||
//pick a new long range goal
|
||||
if( self->ai.state == BOT_STATE_WANDER && self->ai.wander_timeout < level.time)
|
||||
if( self->ai->state == BOT_STATE_WANDER && self->ai->wander_timeout < level.time)
|
||||
AI_PickLongRangeGoal(self);
|
||||
|
||||
//Find any short range goal
|
||||
AI_PickShortRangeGoal(self);
|
||||
|
||||
//run class based states machine
|
||||
self->ai.pers.RunFrame(self);
|
||||
self->ai->pers.RunFrame(self);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -66,7 +66,6 @@ qboolean AI_CanMove(edict_t *self, int direction)
|
|||
VectorSet(offset, 36, 0, -100);
|
||||
G_ProjectSource (self->s.origin, offset, forward, right, end);
|
||||
|
||||
// trap_Trace(&tr, start, NULL, NULL, end, self, MASK_AISOLID);
|
||||
tr = gi.trace( start, NULL, NULL, end, self, MASK_AISOLID );
|
||||
|
||||
if(tr.fraction == 1.0 || tr.contents & (CONTENTS_LAVA|CONTENTS_SLIME))
|
||||
|
@ -208,25 +207,7 @@ qboolean AI_SpecialMove(edict_t *self, usercmd_t *ucmd)
|
|||
if( !tr.startsolid && tr.fraction == 1.0 ) // not bloqued
|
||||
return false;
|
||||
|
||||
if( self->ai.pers.moveTypesMask & LINK_CROUCH || self->ai.is_swim )
|
||||
{
|
||||
//crouch box
|
||||
VectorCopy( self->s.origin, boxorigin );
|
||||
VectorCopy( self->mins, boxmins );
|
||||
VectorCopy( self->maxs, boxmaxs );
|
||||
boxmaxs[2] = 14; //crouched size
|
||||
VectorMA( boxorigin, 8, forward, boxorigin ); //move box by 8 to front
|
||||
//see if bloqued
|
||||
tr = gi.trace( boxorigin, boxmins, boxmaxs, boxorigin, self, MASK_AISOLID);
|
||||
if( !tr.startsolid ) // can move by crouching
|
||||
{
|
||||
ucmd->forwardmove = 400;
|
||||
ucmd->upmove = -400;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if( self->ai.pers.moveTypesMask & LINK_JUMP && self->groundentity )
|
||||
if( self->ai->pers.moveTypesMask & LINK_JUMP && self->groundentity )
|
||||
{
|
||||
//jump box
|
||||
VectorCopy( self->s.origin, boxorigin );
|
||||
|
@ -251,6 +232,24 @@ qboolean AI_SpecialMove(edict_t *self, usercmd_t *ucmd)
|
|||
}
|
||||
}
|
||||
|
||||
if( self->ai->pers.moveTypesMask & LINK_CROUCH || self->is_swim )
|
||||
{
|
||||
//crouch box
|
||||
VectorCopy( self->s.origin, boxorigin );
|
||||
VectorCopy( self->mins, boxmins );
|
||||
VectorCopy( self->maxs, boxmaxs );
|
||||
boxmaxs[2] = 14; //crouched size
|
||||
VectorMA( boxorigin, 8, forward, boxorigin ); //move box by 8 to front
|
||||
//see if bloqued
|
||||
tr = gi.trace( boxorigin, boxmins, boxmaxs, boxorigin, self, MASK_AISOLID);
|
||||
if( !tr.startsolid ) // can move by crouching
|
||||
{
|
||||
ucmd->forwardmove = 400;
|
||||
ucmd->upmove = -400;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//nothing worked, check for turning
|
||||
return AI_CheckEyes(self, ucmd);
|
||||
}
|
||||
|
@ -274,12 +273,12 @@ void AI_ChangeAngle (edict_t *ent)
|
|||
vec3_t ideal_angle;
|
||||
|
||||
// Normalize the move angle first
|
||||
VectorNormalize(ent->ai.move_vector);
|
||||
VectorNormalize(ent->ai->move_vector);
|
||||
|
||||
current_yaw = anglemod(ent->s.angles[YAW]);
|
||||
current_pitch = anglemod(ent->s.angles[PITCH]);
|
||||
|
||||
vectoangles (ent->ai.move_vector, ideal_angle);
|
||||
vectoangles (ent->ai->move_vector, ideal_angle);
|
||||
|
||||
ideal_yaw = anglemod(ideal_angle[YAW]);
|
||||
ideal_pitch = anglemod(ideal_angle[PITCH]);
|
||||
|
@ -360,7 +359,7 @@ qboolean AI_MoveToGoalEntity(edict_t *self, usercmd_t *ucmd)
|
|||
!Q_stricmp(self->movetarget->classname,"grenade") ||
|
||||
!Q_stricmp(self->movetarget->classname,"hgrenade"))
|
||||
{
|
||||
VectorSubtract (self->movetarget->s.origin, self->s.origin, self->ai.move_vector);
|
||||
VectorSubtract (self->movetarget->s.origin, self->s.origin, self->ai->move_vector);
|
||||
AI_ChangeAngle(self);
|
||||
// if(AIDevel.debugChased && bot_showcombat->value)
|
||||
// gi.cprintf(NULL, PRINT_HIGH, "%s: Oh crap a rocket!\n",self->ai.pers.netname);
|
||||
|
@ -375,7 +374,7 @@ qboolean AI_MoveToGoalEntity(edict_t *self, usercmd_t *ucmd)
|
|||
}
|
||||
|
||||
// Set bot's movement direction
|
||||
VectorSubtract (self->movetarget->s.origin, self->s.origin, self->ai.move_vector);
|
||||
VectorSubtract (self->movetarget->s.origin, self->s.origin, self->ai->move_vector);
|
||||
AI_ChangeAngle(self);
|
||||
if(!AI_CanMove(self, BOT_MOVE_FORWARD) )
|
||||
{
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
#include "../header/local.h"
|
||||
#include "ai_local.h"
|
||||
|
||||
#include "astar.h"
|
||||
|
||||
|
||||
//==========================================
|
||||
|
@ -98,34 +98,16 @@ int AI_FindClosestReachableNode( vec3_t origin, edict_t *passent, int range, int
|
|||
return node;
|
||||
}
|
||||
|
||||
//==========================================
|
||||
// AI_SetupPath
|
||||
//==========================================
|
||||
int AI_SetupPath( edict_t *self, int from, int to, int movetypes )
|
||||
{
|
||||
if( self->ai.path != NULL) {
|
||||
free( self->ai.path );
|
||||
self->ai.path = NULL;
|
||||
}
|
||||
|
||||
self->ai.path = malloc( sizeof(astarpath_t) );
|
||||
|
||||
if( !AStar_GetPath( from, to, movetypes, self->ai.path ) )
|
||||
return -1;
|
||||
|
||||
return self->ai.path->numNodes;
|
||||
}
|
||||
|
||||
|
||||
//==========================================
|
||||
// AI_SetGoal
|
||||
// set the goal
|
||||
// set the goal //jabot092
|
||||
//==========================================
|
||||
void AI_SetGoal(edict_t *self, int goal_node)
|
||||
{
|
||||
int node;
|
||||
|
||||
self->ai.goal_node = goal_node;
|
||||
self->ai->goal_node = goal_node;
|
||||
node = AI_FindClosestReachableNode( self->s.origin, self, NODE_DENSITY*3, NODE_ALL );
|
||||
|
||||
if(node == -1) {
|
||||
|
@ -134,28 +116,26 @@ void AI_SetGoal(edict_t *self, int goal_node)
|
|||
}
|
||||
|
||||
//------- ASTAR -----------
|
||||
if(!AI_SetupPath( self, node, goal_node, self->ai.pers.moveTypesMask ))
|
||||
if( !AStar_GetPath( node, goal_node, self->ai->pers.moveTypesMask, &self->ai->path ) )
|
||||
{
|
||||
AI_SetUpMoveWander(self);
|
||||
return;
|
||||
}
|
||||
self->ai.path_position = 0;
|
||||
self->ai.current_node = self->ai.path->nodes[self->ai.path_position];
|
||||
self->ai->current_node = self->ai->path.nodes[self->ai->path.numNodes];
|
||||
//-------------------------
|
||||
|
||||
// if(AIDevel.debugChased && bot_showlrgoal->value)
|
||||
// gi.cprintf(NULL, PRINT_HIGH, "%s: GOAL: new START NODE selected %d\n", self->ai.pers.netname, node);
|
||||
|
||||
self->ai.next_node = self->ai.current_node; // make sure we get to the nearest node first
|
||||
self->ai.node_timeout = 0;
|
||||
|
||||
// gi.cprintf(AIDevel.chaseguy, PRINT_HIGH, "%s: GOAL: new START NODE selected %d\n", self->ai->pers.netname, node);
|
||||
|
||||
self->ai->next_node = self->ai->current_node; // make sure we get to the nearest node first
|
||||
self->ai->node_timeout = 0;
|
||||
}
|
||||
|
||||
|
||||
//==========================================
|
||||
// AI_FollowPath
|
||||
// Move closer to goal by pointing the bot to the next node
|
||||
// that is closer to the goal
|
||||
// that is closer to the goal //jabot092 (path-> to path.)
|
||||
//==========================================
|
||||
qboolean AI_FollowPath( edict_t *self )
|
||||
{
|
||||
|
@ -167,56 +147,57 @@ qboolean AI_FollowPath( edict_t *self )
|
|||
if(bot_showpath->value)
|
||||
{
|
||||
if( AIDevel.debugChased )
|
||||
AITools_DrawPath(self, self->ai.current_node, self->ai.goal_node);
|
||||
AITools_DrawPath(self, self->ai->current_node, self->ai->goal_node);
|
||||
}
|
||||
*/
|
||||
|
||||
if( self->ai.goal_node == INVALID )
|
||||
if( self->ai->goal_node == INVALID )
|
||||
return false;
|
||||
|
||||
// Try again?
|
||||
if(self->ai.node_timeout++ > 30)
|
||||
if(self->ai->node_timeout++ > 30)
|
||||
{
|
||||
if(self->ai.tries++ > 3)
|
||||
if(self->ai->tries++ > 3)
|
||||
return false;
|
||||
else
|
||||
AI_SetGoal( self, self->ai.goal_node );
|
||||
AI_SetGoal( self, self->ai->goal_node );
|
||||
}
|
||||
|
||||
// Are we there yet?
|
||||
VectorSubtract( self->s.origin, nodes[self->ai.next_node].origin, v );
|
||||
VectorSubtract( self->s.origin, nodes[self->ai->next_node].origin, v );
|
||||
dist = VectorLength(v);
|
||||
|
||||
//special lower plat reached check
|
||||
if( dist < 64
|
||||
&& nodes[self->ai.current_node].flags & NODEFLAGS_PLATFORM
|
||||
&& nodes[self->ai.next_node].flags & NODEFLAGS_PLATFORM
|
||||
&& nodes[self->ai->current_node].flags & NODEFLAGS_PLATFORM
|
||||
&& nodes[self->ai->next_node].flags & NODEFLAGS_PLATFORM
|
||||
&& self->groundentity && self->groundentity->use == Use_Plat)
|
||||
dist = 16;
|
||||
|
||||
if( (dist < 32 && nodes[self->ai.next_node].flags != NODEFLAGS_JUMPPAD && nodes[self->ai.next_node].flags != NODEFLAGS_TELEPORTER_IN)
|
||||
|| (self->ai.status.jumpadReached && nodes[self->ai.next_node].flags & NODEFLAGS_JUMPPAD)
|
||||
|| (self->ai.status.TeleportReached && nodes[self->ai.next_node].flags & NODEFLAGS_TELEPORTER_IN) )
|
||||
if( (dist < 32 && nodes[self->ai->next_node].flags != NODEFLAGS_JUMPPAD && nodes[self->ai->next_node].flags != NODEFLAGS_TELEPORTER_IN)
|
||||
|| (self->ai->status.jumpadReached && nodes[self->ai->next_node].flags & NODEFLAGS_JUMPPAD)
|
||||
|| (self->ai->status.TeleportReached && nodes[self->ai->next_node].flags & NODEFLAGS_TELEPORTER_IN) )
|
||||
{
|
||||
// reset timeout
|
||||
self->ai.node_timeout = 0;
|
||||
self->ai->node_timeout = 0;
|
||||
|
||||
if( self->ai.next_node == self->ai.goal_node )
|
||||
if( self->ai->next_node == self->ai->goal_node )
|
||||
{
|
||||
// if(AIDevel.debugChased && bot_showlrgoal->value)
|
||||
// gi.cprintf(NULL, PRINT_HIGH, "%s: GOAL REACHED!\n", self->ai.pers.netname);
|
||||
//if(AIDevel.debugChased && bot_showlrgoal->value)
|
||||
// gi.cprintf(AIDevel.chaseguy, PRINT_HIGH, "%s: GOAL REACHED!\n", self->ai->pers.netname);
|
||||
|
||||
//if botroam, setup a timeout for it
|
||||
if( nodes[self->ai.goal_node].flags & NODEFLAGS_BOTROAM )
|
||||
if( nodes[self->ai->goal_node].flags & NODEFLAGS_BOTROAM )
|
||||
{
|
||||
int i;
|
||||
for( i=0; i<nav.num_broams; i++) { //find the broam
|
||||
if( nav.broams[i].node != self->ai.goal_node )
|
||||
if( nav.broams[i].node != self->ai->goal_node )
|
||||
continue;
|
||||
|
||||
// if(AIDevel.debugChased && bot_showlrgoal->value)
|
||||
// gi.cprintf(NULL, PRINT_HIGH, "%s: BotRoam Time Out set up for node %i\n", self->ai.pers.netname, nav.broams[i].node);
|
||||
self->ai.status.broam_timeouts[i] = level.time + 15.0;
|
||||
//if(AIDevel.debugChased && bot_showlrgoal->integer)
|
||||
// gi.cprintf(AIDevel.chaseguy, PRINT_HIGH, "%s: BotRoam Time Out set up for node %i\n", self->ai->pers.netname, nav.broams[i].node);
|
||||
//Com_Printf( "%s: BotRoam Time Out set up for node %i\n", self->ai->pers.netname, nav.broams[i].node);
|
||||
self->ai->status.broam_timeouts[i] = level.time + 15.0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -226,20 +207,17 @@ qboolean AI_FollowPath( edict_t *self )
|
|||
}
|
||||
else
|
||||
{
|
||||
self->ai.current_node = self->ai.next_node;
|
||||
self->ai.next_node = self->ai.path->nodes[self->ai.path_position++];
|
||||
|
||||
// if(AIDevel.debugChased && bot_showpath->value > 1 )
|
||||
// gi.cprintf(NULL, PRINT_HIGH, "%s: CurrentNode(%i):%s NextNode(%i):%s\n", self->ai.pers.netname, self->ai.current_node, nodeTypeNames[nodes[self->ai.current_node].type], self->ai.next_node, nodeTypeNames[nodes[self->ai.next_node].type]);
|
||||
|
||||
self->ai->current_node = self->ai->next_node;
|
||||
if( self->ai->path.numNodes )
|
||||
self->ai->path.numNodes--;
|
||||
self->ai->next_node = self->ai->path.nodes[self->ai->path.numNodes];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if( self->ai.current_node == -1 || self->ai.next_node == -1 )
|
||||
if(self->ai->current_node == -1 || self->ai->next_node == -1)
|
||||
return false;
|
||||
|
||||
// Set bot's movement vector
|
||||
VectorSubtract( nodes[self->ai.next_node].origin, self->s.origin , self->ai.move_vector );
|
||||
VectorSubtract( nodes[self->ai->next_node].origin, self->s.origin , self->ai->move_vector );
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ qboolean AI_DropNodeOriginToFloor( vec3_t origin, edict_t *passent )
|
|||
{
|
||||
trace_t trace;
|
||||
|
||||
//trap_Trace ( &trace, origin, tv(-15, -15, 0), tv(15, 15, 0), tv(origin[0], origin[1], world->mins[2]), NULL, MASK_NODESOLID );//jalfixme. 0?
|
||||
//trap_Trace ( &trace, origin, tv(-15, -15, 0), tv(15, 15, 0), tv(origin[0], origin[1], world->mins[2]), NULL, MASK_NODESOLID );
|
||||
trace = gi.trace( origin, tv(-15, -15, 0), tv(15, 15, 0), tv(origin[0], origin[1], origin[2]-2048), passent, MASK_NODESOLID );
|
||||
if( trace.startsolid )
|
||||
return false;
|
||||
|
@ -109,16 +109,16 @@ void AI_JumpadGuess_ShowPoint( vec3_t origin, char *modelname )
|
|||
ent->movetype = MOVETYPE_NONE;
|
||||
ent->clipmask = MASK_WATER;
|
||||
ent->solid = SOLID_NOT;
|
||||
ent->s.type = ET_GENERIC;
|
||||
ent->s.renderfx |= RF_NOSHADOW;
|
||||
// ent->s.type = ET_GENERIC;
|
||||
// ent->s.renderfx |= RF_NOSHADOW;
|
||||
VectorClear ( ent->mins );
|
||||
VectorClear ( ent->maxs );
|
||||
ent->s.modelindex = trap_ModelIndex ( modelname );
|
||||
ent->s.modelindex = gi.modelindex ( modelname );
|
||||
ent->nextthink = level.time + 20000;
|
||||
ent->think = G_FreeEdict;
|
||||
ent->classname = "checkent";
|
||||
|
||||
trap_LinkEntity (ent);
|
||||
gi.linkentity (ent);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -139,6 +139,9 @@ qboolean AI_PredictJumpadDestity( edict_t *ent, vec3_t out )
|
|||
|
||||
VectorClear( out );
|
||||
|
||||
if( !ent->target ) //jabot092
|
||||
return false;
|
||||
|
||||
// get target entity
|
||||
target = G_Find ( NULL, FOFS(targetname), ent->target );
|
||||
if (!target)
|
||||
|
@ -157,7 +160,6 @@ qboolean AI_PredictJumpadDestity( edict_t *ent, vec3_t out )
|
|||
floor_target_origin[2] = pad_origin[2]; //put at pad's height
|
||||
|
||||
//make a guess on how player movement will affect the trajectory
|
||||
//tmpfloat = Distance( pad_origin, floor_target_origin );
|
||||
tmpfloat = AI_Distance( pad_origin, floor_target_origin );
|
||||
htime = sqrt ((tmpfloat));
|
||||
vtime = sqrt ((target->s.origin[2] - pad_origin[2]));
|
||||
|
@ -185,7 +187,7 @@ qboolean AI_PredictJumpadDestity( edict_t *ent, vec3_t out )
|
|||
|
||||
#ifdef SHOW_JUMPAD_GUESS
|
||||
// this is our top of the curve point, and the original target
|
||||
AI_JumpadGuess_ShowPoint( target_origin, "models/powerups/health/mega_sphere.md3" );
|
||||
AI_JumpadGuess_ShowPoint( target_origin, "models/objects/grenade2/tris.md2" );
|
||||
AI_JumpadGuess_ShowPoint( target->s.origin, "models/powerups/health/large_cross.md3" );
|
||||
#endif
|
||||
|
||||
|
@ -214,7 +216,7 @@ qboolean AI_PredictJumpadDestity( edict_t *ent, vec3_t out )
|
|||
|
||||
#ifdef SHOW_JUMPAD_GUESS
|
||||
// destiny found
|
||||
AI_JumpadGuess_ShowPoint( trace.endpos, "models/powerups/health/mega_sphere.md3" );
|
||||
AI_JumpadGuess_ShowPoint( trace.endpos, "models/objects/grenade2/tris.md2" );
|
||||
#endif
|
||||
|
||||
VectorCopy ( trace.endpos, out );
|
||||
|
@ -270,7 +272,7 @@ int AI_AddNode_JumpPad( edict_t *ent )
|
|||
|
||||
|
||||
//==========================================
|
||||
// AI_AddNode_Door
|
||||
// AI_AddNode_Door - //jabot092(2)
|
||||
// Drop a node at each side of the door
|
||||
// and force them to link. Only typical
|
||||
// doors are covered.
|
||||
|
@ -279,8 +281,10 @@ int AI_AddNode_Door( edict_t *ent )
|
|||
{
|
||||
edict_t *other;
|
||||
vec3_t mins, maxs;
|
||||
vec3_t forward, right, up;
|
||||
vec3_t door_origin;
|
||||
vec3_t crossdir;
|
||||
vec3_t MOVEDIR_UP = {0, 0, 1};
|
||||
vec3_t MOVEDIR_DOWN = {0, 0, -1};
|
||||
|
||||
if (ent->flags & FL_TEAMSLAVE)
|
||||
return INVALID; //only team master will drop the nodes
|
||||
|
@ -299,56 +303,108 @@ int AI_AddNode_Door( edict_t *ent )
|
|||
door_origin[1] = (maxs[1] - mins[1]) / 2 + mins[1];
|
||||
door_origin[2] = (maxs[2] - mins[2]) / 2 + mins[2];
|
||||
|
||||
//now find the crossing angle
|
||||
AngleVectors( ent->s.angles, forward, right, up );
|
||||
VectorNormalize( right );
|
||||
|
||||
//if it moves in y axis we don't know if it's walked to north or east, so
|
||||
// we must try dropping nodes in both directions and check for solids
|
||||
if (VectorCompare(MOVEDIR_UP, ent->movedir) || VectorCompare(MOVEDIR_DOWN, ent->movedir) )
|
||||
{
|
||||
//now find the crossing angle
|
||||
AngleVectors( ent->s.angles, crossdir, NULL, NULL );
|
||||
VectorNormalize( crossdir );
|
||||
|
||||
//add node
|
||||
nodes[nav.num_nodes].flags = 0;
|
||||
VectorMA( door_origin, 32, crossdir, nodes[nav.num_nodes].origin);
|
||||
if( AI_DropNodeOriginToFloor( nodes[nav.num_nodes].origin, NULL ) )
|
||||
{
|
||||
nodes[nav.num_nodes].flags |= AI_FlagsForNode( nodes[nav.num_nodes].origin, NULL );
|
||||
#ifdef SHOW_JUMPAD_GUESS
|
||||
AI_JumpadGuess_ShowPoint( nodes[nav.num_nodes].origin, "models/objects/grenade2/tris.md2" );
|
||||
#endif
|
||||
nav.num_nodes++;
|
||||
}
|
||||
|
||||
//add node 2
|
||||
nodes[nav.num_nodes].flags = 0;
|
||||
VectorMA( door_origin, -32, crossdir, nodes[nav.num_nodes].origin);
|
||||
if( AI_DropNodeOriginToFloor( nodes[nav.num_nodes].origin, NULL ) )
|
||||
{
|
||||
nodes[nav.num_nodes].flags |= AI_FlagsForNode( nodes[nav.num_nodes].origin, NULL );
|
||||
#ifdef SHOW_JUMPAD_GUESS
|
||||
AI_JumpadGuess_ShowPoint( nodes[nav.num_nodes].origin, "models/objects/grenade2/tris.md2" );
|
||||
#endif
|
||||
//add links in both directions
|
||||
AI_AddLink( nav.num_nodes, nav.num_nodes-1, LINK_MOVE );
|
||||
AI_AddLink( nav.num_nodes-1, nav.num_nodes, LINK_MOVE );
|
||||
|
||||
nav.num_nodes++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//find the crossing angle
|
||||
AngleVectors( ent->s.angles, NULL, crossdir, NULL ); //jabot092(2)
|
||||
VectorNormalize( crossdir );
|
||||
|
||||
//add node
|
||||
nodes[nav.num_nodes].flags = 0/*NODEFLAGS_SERVERLINK*/;
|
||||
VectorMA( door_origin, 32, right, nodes[nav.num_nodes].origin);
|
||||
AI_DropNodeOriginToFloor( nodes[nav.num_nodes].origin, NULL );
|
||||
nodes[nav.num_nodes].flags |= AI_FlagsForNode( nodes[nav.num_nodes].origin, NULL );
|
||||
nodes[nav.num_nodes].flags = 0;
|
||||
VectorMA( door_origin, 32, crossdir, nodes[nav.num_nodes].origin);
|
||||
if( AI_DropNodeOriginToFloor( nodes[nav.num_nodes].origin, NULL ) )
|
||||
{
|
||||
nodes[nav.num_nodes].flags |= AI_FlagsForNode( nodes[nav.num_nodes].origin, NULL );
|
||||
#ifdef SHOW_JUMPAD_GUESS
|
||||
AI_JumpadGuess_ShowPoint( nodes[nav.num_nodes].origin, "models/powerups/health/mega_sphere.md3" );
|
||||
AI_JumpadGuess_ShowPoint( nodes[nav.num_nodes].origin, "models/objects/grenade2/tris.md2" );
|
||||
#endif
|
||||
nav.num_nodes++;
|
||||
nav.num_nodes++;
|
||||
}
|
||||
|
||||
//add node 2
|
||||
nodes[nav.num_nodes].flags = 0/*NODEFLAGS_SERVERLINK*/;
|
||||
VectorMA( door_origin, -32, right, nodes[nav.num_nodes].origin);
|
||||
AI_DropNodeOriginToFloor( nodes[nav.num_nodes].origin, NULL );
|
||||
nodes[nav.num_nodes].flags |= AI_FlagsForNode( nodes[nav.num_nodes].origin, NULL );
|
||||
nodes[nav.num_nodes].flags = 0;
|
||||
VectorMA( door_origin, -32, crossdir, nodes[nav.num_nodes].origin);
|
||||
if( AI_DropNodeOriginToFloor( nodes[nav.num_nodes].origin, NULL ) )
|
||||
{
|
||||
nodes[nav.num_nodes].flags |= AI_FlagsForNode( nodes[nav.num_nodes].origin, NULL );
|
||||
#ifdef SHOW_JUMPAD_GUESS
|
||||
AI_JumpadGuess_ShowPoint( nodes[nav.num_nodes].origin, "models/powerups/health/mega_sphere.md3" );
|
||||
AI_JumpadGuess_ShowPoint( nodes[nav.num_nodes].origin, "models/objects/grenade2/tris.md2" );
|
||||
#endif
|
||||
//add links in both directions
|
||||
AI_AddLink( nav.num_nodes, nav.num_nodes-1, LINK_MOVE );
|
||||
AI_AddLink( nav.num_nodes-1, nav.num_nodes, LINK_MOVE );
|
||||
//add links in both directions
|
||||
AI_AddLink( nav.num_nodes, nav.num_nodes-1, LINK_MOVE );
|
||||
AI_AddLink( nav.num_nodes-1, nav.num_nodes, LINK_MOVE );
|
||||
|
||||
nav.num_nodes++;
|
||||
}
|
||||
|
||||
nav.num_nodes++;
|
||||
return nav.num_nodes-1;
|
||||
}
|
||||
|
||||
|
||||
//==========================================
|
||||
// AI_AddNode_Platform
|
||||
// AI_AddNode_Platform - //jabot092(2)
|
||||
// drop two nodes one at top, one at bottom
|
||||
//==========================================
|
||||
int AI_AddNode_Platform( edict_t *ent )
|
||||
{
|
||||
vec3_t v1,v2;
|
||||
float plat_dist;
|
||||
|
||||
if (nav.num_nodes + 1 > MAX_NODES)
|
||||
if (nav.num_nodes + 2 > MAX_NODES)
|
||||
return INVALID;
|
||||
|
||||
if (ent->flags & FL_TEAMSLAVE)
|
||||
return INVALID; //only team master will drop the nodes
|
||||
|
||||
plat_dist = ent->pos1[2] - ent->pos2[2]; //jabot092(2)
|
||||
|
||||
// Upper node
|
||||
nodes[nav.num_nodes].flags = (NODEFLAGS_PLATFORM|NODEFLAGS_SERVERLINK|NODEFLAGS_FLOAT);
|
||||
VectorCopy( ent->maxs, v1 );
|
||||
VectorCopy( ent->mins, v2 );
|
||||
nodes[nav.num_nodes].origin[0] = (v1[0] - v2[0]) / 2 + v2[0];
|
||||
nodes[nav.num_nodes].origin[1] = (v1[1] - v2[1]) / 2 + v2[1];
|
||||
nodes[nav.num_nodes].origin[2] = ent->maxs[2] + 8;
|
||||
|
||||
nodes[nav.num_nodes].origin[2] = ent->mins[2] + plat_dist + 16;//jabot092(2)
|
||||
#ifdef SHOW_JUMPAD_GUESS
|
||||
AI_JumpadGuess_ShowPoint( nodes[nav.num_nodes].origin, "models/objects/grenade2/tris.md2" );
|
||||
#endif
|
||||
nodes[nav.num_nodes].flags |= AI_FlagsForNode( nodes[nav.num_nodes].origin, NULL );
|
||||
|
||||
//put into ents table
|
||||
|
@ -362,8 +418,10 @@ int AI_AddNode_Platform( edict_t *ent )
|
|||
nodes[nav.num_nodes].flags = (NODEFLAGS_PLATFORM|NODEFLAGS_SERVERLINK|NODEFLAGS_FLOAT);
|
||||
nodes[nav.num_nodes].origin[0] = nodes[nav.num_nodes-1].origin[0];
|
||||
nodes[nav.num_nodes].origin[1] = nodes[nav.num_nodes-1].origin[1];
|
||||
nodes[nav.num_nodes].origin[2] = ent->mins[2] + (AI_JUMPABLE_HEIGHT - 1);
|
||||
|
||||
nodes[nav.num_nodes].origin[2] = ent->mins[2] + (AI_JUMPABLE_HEIGHT - 1); //jabot092(2)
|
||||
#ifdef SHOW_JUMPAD_GUESS
|
||||
AI_JumpadGuess_ShowPoint( nodes[nav.num_nodes].origin, "models/objects/grenade2/tris.md2" );
|
||||
#endif
|
||||
nodes[nav.num_nodes].flags |= AI_FlagsForNode( nodes[nav.num_nodes].origin, NULL );
|
||||
|
||||
//put into ents table
|
||||
|
@ -909,13 +967,13 @@ void AI_InitNavigationData(void)
|
|||
return;
|
||||
}
|
||||
|
||||
servernodesstart = nav.num_nodes;
|
||||
|
||||
for( linkscount = 0, i = 0; i< nav.num_nodes; i++ )
|
||||
{
|
||||
linkscount += pLinks[i].numLinks;
|
||||
}
|
||||
|
||||
servernodesstart = nav.num_nodes;
|
||||
|
||||
//create nodes for map entities
|
||||
AI_CreateNodesForEntities();
|
||||
newlinks = AI_LinkServerNodes( servernodesstart );
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
//
|
||||
//=============================================================
|
||||
|
||||
#define MAX_NODES 2048 //jalToDo: needs dynamic alloc (big terrain maps)
|
||||
#define NODE_DENSITY 128 // Density setting for nodes
|
||||
#define INVALID -1
|
||||
#define NODES_MAX_PLINKS 16
|
||||
|
|
|
@ -30,8 +30,8 @@
|
|||
//
|
||||
//==========================================
|
||||
|
||||
static int alist[MAX_NODES]; //list contains all studied nodes, Open and Closed together
|
||||
static int alist_numNodes;
|
||||
static int alist[MAX_NODES]; //list contains all studied nodes, Open and Closed together
|
||||
static int alist_numNodes;
|
||||
|
||||
enum {
|
||||
NOLIST,
|
||||
|
@ -41,18 +41,17 @@ enum {
|
|||
|
||||
typedef struct
|
||||
{
|
||||
int parent;
|
||||
int parent;
|
||||
int G;
|
||||
int H;
|
||||
|
||||
int list;
|
||||
int list;
|
||||
|
||||
} astarnode_t;
|
||||
|
||||
astarnode_t astarnodes[MAX_NODES];
|
||||
|
||||
static int Apath[MAX_NODES];
|
||||
static int Apath_numNodes;
|
||||
struct astarpath_s *Apath;
|
||||
//==========================================
|
||||
//
|
||||
//
|
||||
|
@ -61,8 +60,7 @@ static int originNode;
|
|||
static int goalNode;
|
||||
static int currentNode;
|
||||
|
||||
int ValidLinksMask;
|
||||
|
||||
static int ValidLinksMask;
|
||||
#define DEFAULT_MOVETYPES_MASK ( \
|
||||
LINK_MOVE | \
|
||||
LINK_STAIRS | \
|
||||
|
@ -71,30 +69,13 @@ int ValidLinksMask;
|
|||
LINK_WATERJUMP | \
|
||||
LINK_JUMPPAD | \
|
||||
LINK_PLATFORM | \
|
||||
LINK_TELEPORT);
|
||||
|
||||
LINK_TELEPORT)
|
||||
//==========================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================
|
||||
|
||||
int AStar_nodeIsInPath(int node)
|
||||
{
|
||||
int i;
|
||||
|
||||
if( !Apath_numNodes )
|
||||
return 0;
|
||||
|
||||
for (i=0; i<Apath_numNodes; i++)
|
||||
{
|
||||
if(node == Apath[i])
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AStar_nodeIsInClosed( int node )
|
||||
{
|
||||
if( astarnodes[node].list == CLOSEDLIST )
|
||||
|
@ -117,38 +98,33 @@ static void AStar_InitLists (void)
|
|||
|
||||
for ( i=0; i<MAX_NODES; i++ )
|
||||
{
|
||||
Apath[i] = 0;
|
||||
|
||||
astarnodes[i].G = 0;
|
||||
astarnodes[i].H = 0;
|
||||
astarnodes[i].parent = 0;
|
||||
astarnodes[i].list = NOLIST;
|
||||
}
|
||||
Apath_numNodes = 0;
|
||||
|
||||
if( Apath )
|
||||
Apath->numNodes = 0;
|
||||
|
||||
alist_numNodes = 0;
|
||||
for( i=0; i<MAX_NODES; i++ )
|
||||
alist[i] = -1;
|
||||
memset( alist, -1, sizeof(alist));//jabot092
|
||||
}
|
||||
|
||||
static int AStar_PLinkDistance(int n1, int n2)
|
||||
static int
|
||||
AStar_PLinkDistance(int n1, int n2)
|
||||
{
|
||||
int i;
|
||||
int found = 0;
|
||||
int dist;
|
||||
int i;
|
||||
|
||||
for ( i=0; i<pLinks[n1].numLinks; i++)
|
||||
{
|
||||
if( pLinks[n1].nodes[i] == n2 ) {
|
||||
found = 1;
|
||||
dist = (int)pLinks[n1].dist[i];
|
||||
if (pLinks[n1].nodes[i] == n2)
|
||||
{
|
||||
return (int)pLinks[n1].dist[i];
|
||||
}
|
||||
}
|
||||
|
||||
if(!found)
|
||||
return -1;
|
||||
|
||||
return dist;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int Astar_HDist_ManhatanGuess( int node )
|
||||
|
@ -165,11 +141,7 @@ static int Astar_HDist_ManhatanGuess( int node )
|
|||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
DistVec[i] = nodes[goalNode].origin[i] - nodes[node].origin[i];
|
||||
if( DistVec[i] < 0.0f )
|
||||
{
|
||||
DistVec[i] = -DistVec[i]; //use only positive values. We don't care about direction.
|
||||
}
|
||||
DistVec[i] = fabs(nodes[goalNode].origin[i] - nodes[node].origin[i]);
|
||||
}
|
||||
|
||||
HDist = (int)(DistVec[0] + DistVec[1] + DistVec[2]);
|
||||
|
@ -187,7 +159,8 @@ static void AStar_PutInClosed( int node )
|
|||
astarnodes[node].list = CLOSEDLIST;
|
||||
}
|
||||
|
||||
static void AStar_PutAdjacentsInOpen(int node)
|
||||
static void
|
||||
AStar_PutAdjacentsInOpen(int node)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -232,9 +205,7 @@ static void AStar_PutAdjacentsInOpen(int node)
|
|||
astarnodes[addnode].G = astarnodes[node].G + plinkDist;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{ //just put it in
|
||||
} else { //just put it in
|
||||
|
||||
int plinkDist;
|
||||
|
||||
|
@ -243,9 +214,7 @@ static void AStar_PutAdjacentsInOpen(int node)
|
|||
{
|
||||
plinkDist = AStar_PLinkDistance( addnode, node );
|
||||
if( plinkDist == -1)
|
||||
{
|
||||
plinkDist = 999;//jalFIXME
|
||||
}
|
||||
|
||||
if (bot_debugmonster->value)
|
||||
{
|
||||
|
@ -302,21 +271,19 @@ static void AStar_ListsToPath ( void )
|
|||
{
|
||||
int count = 0;
|
||||
int cur = goalNode;
|
||||
int *pnode;
|
||||
|
||||
Apath->numNodes = 0;
|
||||
pnode = Apath->nodes;
|
||||
while ( cur != originNode )
|
||||
{
|
||||
*pnode = cur;
|
||||
pnode++;
|
||||
cur = astarnodes[cur].parent;
|
||||
count++;
|
||||
}
|
||||
cur = goalNode;
|
||||
|
||||
while ( count >= 0 )
|
||||
{
|
||||
Apath[count] = cur;
|
||||
Apath_numNodes++;
|
||||
count--;
|
||||
cur = astarnodes[cur].parent;
|
||||
}
|
||||
Apath->numNodes = count-1;
|
||||
}
|
||||
|
||||
static int AStar_FillLists ( void )
|
||||
|
@ -333,7 +300,7 @@ static int AStar_FillLists ( void )
|
|||
return (currentNode != -1); //if -1 path is bloqued
|
||||
}
|
||||
|
||||
int AStar_ResolvePath ( int n1, int n2, int movetypes )
|
||||
static int AStar_ResolvePath ( int n1, int n2, int movetypes )
|
||||
{
|
||||
ValidLinksMask = movetypes;
|
||||
if ( !ValidLinksMask )
|
||||
|
@ -357,30 +324,20 @@ int AStar_ResolvePath ( int n1, int n2, int movetypes )
|
|||
|
||||
AStar_ListsToPath();
|
||||
|
||||
if (bot_debugmonster->value)
|
||||
{
|
||||
Com_Printf("RESULT:\n Origin:%i\n Goal:%i\n numNodes:%i\n FirstInPath:%i\n LastInPath:%i\n",
|
||||
originNode, goalNode, Apath_numNodes, Apath[0], Apath[Apath_numNodes-1]);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int AStar_GetPath( int origin, int goal, int movetypes, struct astarpath_s *path )
|
||||
int
|
||||
AStar_GetPath(int origin, int goal, int movetypes, struct astarpath_s *path)
|
||||
{
|
||||
int i;
|
||||
Apath = path;
|
||||
|
||||
if( !AStar_ResolvePath ( origin, goal, movetypes ) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
path->numNodes = Apath_numNodes;
|
||||
path->originNode = origin;
|
||||
path->goalNode = goal;
|
||||
for(i=0; i<path->numNodes; i++)
|
||||
{
|
||||
path->nodes[i] = Apath[i];
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -28,20 +28,6 @@
|
|||
* in NO WAY supported by Steve Yeager.
|
||||
*/
|
||||
|
||||
//==========================================
|
||||
//
|
||||
//
|
||||
//==========================================
|
||||
|
||||
typedef struct astarpath_s
|
||||
{
|
||||
int numNodes;
|
||||
int nodes[MAX_NODES];
|
||||
int originNode;
|
||||
int goalNode;
|
||||
|
||||
} astarpath_t;
|
||||
|
||||
// A* PROPS
|
||||
//===========================================
|
||||
int AStar_nodeIsInClosed( int node );
|
||||
|
|
|
@ -93,7 +93,7 @@ void safe_cprintf (edict_t *ent, int printlevel, char *fmt, ...)
|
|||
char bigbuffer[0x10000];
|
||||
va_list argptr;
|
||||
|
||||
if (ent && (!ent->inuse || ent->ai.is_bot))
|
||||
if (ent && (!ent->inuse || ent->ai))
|
||||
return;
|
||||
|
||||
va_start (argptr,fmt);
|
||||
|
@ -112,7 +112,7 @@ void safe_centerprintf (edict_t *ent, char *fmt, ...)
|
|||
char bigbuffer[0x10000];
|
||||
va_list argptr;
|
||||
|
||||
if (!ent->inuse || ent->ai.is_bot)
|
||||
if (!ent->inuse || ent->ai)
|
||||
return;
|
||||
|
||||
va_start (argptr,fmt);
|
||||
|
@ -143,7 +143,7 @@ void safe_bprintf (int printlevel, char *fmt, ...)
|
|||
for (i=0 ; i<maxclients->value ; i++)
|
||||
{
|
||||
cl_ent = g_edicts + 1 + i;
|
||||
if (!cl_ent->inuse || cl_ent->ai.is_bot)
|
||||
if (!cl_ent->inuse || cl_ent->ai)
|
||||
continue;
|
||||
|
||||
gi.cprintf(cl_ent, printlevel, bigbuffer);
|
||||
|
|
|
@ -64,37 +64,30 @@ void BOT_Respawn (edict_t *self)
|
|||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Find a free client spot
|
||||
// Find a free client spot - //jabot092(2)
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
edict_t *BOT_FindFreeClient (void)
|
||||
{
|
||||
edict_t *bot;
|
||||
edict_t *ent;
|
||||
int i;
|
||||
int max_count=0;
|
||||
|
||||
// This is for the naming of the bots
|
||||
for (i = maxclients->value; i > 0; i--)
|
||||
bot = NULL;
|
||||
for( i = 0, ent = g_edicts + 1; i < game.maxclients; i++, ent++ )
|
||||
{
|
||||
bot = g_edicts + i + 1;
|
||||
if( !ent->inuse && bot == NULL )
|
||||
bot = ent;
|
||||
|
||||
if(bot->count > max_count)
|
||||
max_count = bot->count;
|
||||
//count bots for bot names
|
||||
if( ent->count > max_count )
|
||||
max_count = ent->count;
|
||||
}
|
||||
|
||||
// Check for free spot
|
||||
for (i = maxclients->value; i > 0; i--)
|
||||
{
|
||||
bot = g_edicts + i + 1;
|
||||
|
||||
if (!bot->inuse)
|
||||
break;
|
||||
}
|
||||
if (bot == NULL || (max_count + 2) >= game.maxclients ) //always leave room for 1 player
|
||||
return NULL;
|
||||
|
||||
bot->count = max_count + 1; // Will become bot name...
|
||||
|
||||
if (bot->inuse)
|
||||
bot = NULL;
|
||||
|
||||
return bot;
|
||||
}
|
||||
|
||||
|
@ -173,8 +166,6 @@ void BOT_SetName(edict_t *bot, char *name, char *skin, char *team)
|
|||
Info_SetValueForKey (userinfo, "hand", "2"); // bot is center handed for now!
|
||||
|
||||
ClientConnect (bot, userinfo);
|
||||
|
||||
// ACESP_SaveBots(); // make sure to save the bots
|
||||
}
|
||||
|
||||
//==========================================
|
||||
|
@ -330,13 +321,12 @@ void BOT_SpawnBot (char *team, char *name, char *skin, char *userinfo)
|
|||
|
||||
if (!bot)
|
||||
{
|
||||
// safe_bprintf (PRINT_MEDIUM, "Server is full, increase Maxclients.\n");
|
||||
safe_bprintf (PRINT_MEDIUM, "Server is full, increase Maxclients.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
//init the bot
|
||||
bot->inuse = true;
|
||||
bot->ai.is_bot = true;
|
||||
bot->yaw_speed = 100;
|
||||
|
||||
// To allow bots to respawn
|
||||
|
@ -346,17 +336,19 @@ void BOT_SpawnBot (char *team, char *name, char *skin, char *userinfo)
|
|||
ClientConnect (bot, userinfo);
|
||||
|
||||
G_InitEdict (bot);
|
||||
G_SpawnAI(bot); //jabot092(2)
|
||||
bot->ai->is_bot = true;
|
||||
InitClientResp (bot->client);
|
||||
|
||||
PutClientInServer(bot);
|
||||
BOT_StartAsSpectator (bot);
|
||||
|
||||
//skill
|
||||
bot->ai.pers.skillLevel = (int)(random()*MAX_BOT_SKILL);
|
||||
if (bot->ai.pers.skillLevel > MAX_BOT_SKILL) //fix if off-limits
|
||||
bot->ai.pers.skillLevel = MAX_BOT_SKILL;
|
||||
else if (bot->ai.pers.skillLevel < 0)
|
||||
bot->ai.pers.skillLevel = 0;
|
||||
bot->ai->pers.skillLevel = (int)(random()*MAX_BOT_SKILL);
|
||||
if (bot->ai->pers.skillLevel > MAX_BOT_SKILL) //fix if off-limits
|
||||
bot->ai->pers.skillLevel = MAX_BOT_SKILL;
|
||||
else if (bot->ai->pers.skillLevel < 0)
|
||||
bot->ai->pers.skillLevel = 0;
|
||||
|
||||
BOT_DMclass_InitPersistant(bot);
|
||||
AI_ResetWeights(bot);
|
||||
|
@ -387,23 +379,19 @@ void BOT_RemoveBot(char *name)
|
|||
for(i=0;i<maxclients->value;i++)
|
||||
{
|
||||
bot = g_edicts + i + 1;
|
||||
if(bot->inuse)
|
||||
if( !bot->inuse || !bot->ai ) //jabot092(2)
|
||||
continue;
|
||||
|
||||
if( bot->ai->is_bot && (!strcmp(bot->client->pers.netname,name) || !strcmp(name,"all")))
|
||||
{
|
||||
if(bot->ai.is_bot && (strcmp(bot->client->pers.netname,name)==0 || strcmp(name,"all")==0))
|
||||
{
|
||||
bot->health = 0;
|
||||
player_die (bot, bot, bot, 100000, vec3_origin);
|
||||
// don't even bother waiting for death frames
|
||||
bot->deadflag = DEAD_DEAD;
|
||||
bot->inuse = false;
|
||||
AI_EnemyRemoved (bot);
|
||||
// safe_bprintf (PRINT_MEDIUM, "%s removed\n", bot->client->pers.netname);
|
||||
}
|
||||
bot->health = 0;
|
||||
player_die (bot, bot, bot, 100000, vec3_origin);
|
||||
// don't even bother waiting for death frames
|
||||
bot->deadflag = DEAD_DEAD;
|
||||
bot->inuse = false;
|
||||
AI_EnemyRemoved (bot);
|
||||
G_FreeAI( bot ); //jabot092(2)
|
||||
//safe_bprintf (PRINT_MEDIUM, "%s removed\n", bot->client->pers.netname);
|
||||
}
|
||||
}
|
||||
|
||||
// if(!freed)
|
||||
// safe_bprintf (PRINT_MEDIUM, "%s not found\n", name);
|
||||
|
||||
// ACESP_SaveBots(); // Save them again
|
||||
}
|
||||
|
|
|
@ -522,10 +522,9 @@ G_RunFrame(void)
|
|||
{
|
||||
ClientBeginServerFrame(ent);
|
||||
//JABot[start]
|
||||
if ( ent->ai.is_bot )
|
||||
G_RunEntity (ent);
|
||||
if (!ent->ai)
|
||||
//[end]
|
||||
continue;
|
||||
continue;
|
||||
}
|
||||
|
||||
G_RunEntity(ent);
|
||||
|
|
|
@ -31,6 +31,15 @@
|
|||
// declaration of botedict for the game
|
||||
//----------------------------------------------------------
|
||||
#define MAX_BOT_ROAMS 128
|
||||
#define MAX_NODES 2048 //jalToDo: needs dynamic alloc (big terrain maps)
|
||||
|
||||
typedef struct astarpath_s
|
||||
{
|
||||
int numNodes;
|
||||
int nodes[MAX_NODES];
|
||||
int originNode;
|
||||
int goalNode;
|
||||
} astarpath_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
@ -70,12 +79,6 @@ typedef struct
|
|||
int state; // Bot State (WANDER, MOVE, etc)
|
||||
float state_combat_timeout;
|
||||
|
||||
qboolean is_swim;
|
||||
qboolean is_step;
|
||||
qboolean is_ladder;
|
||||
qboolean was_swim;
|
||||
qboolean was_step;
|
||||
|
||||
// movement
|
||||
vec3_t move_vector;
|
||||
float next_move_time;
|
||||
|
@ -91,8 +94,7 @@ typedef struct
|
|||
|
||||
int tries;
|
||||
|
||||
struct astarpath_s *path;
|
||||
int path_position;
|
||||
struct astarpath_s path; //jabot092
|
||||
|
||||
int nearest_node_tries; //for increasing radius of search with each try
|
||||
|
||||
|
@ -105,6 +107,8 @@ qboolean BOT_ServerCommand(void);
|
|||
// ai_main.c
|
||||
void AI_Init(void);
|
||||
void AI_NewMap(void);
|
||||
void G_FreeAI( edict_t *ent );
|
||||
void G_SpawnAI( edict_t *ent );
|
||||
|
||||
// ai_items.c
|
||||
void AI_EnemyAdded(edict_t *ent);
|
||||
|
|
|
@ -1517,7 +1517,12 @@ struct edict_s
|
|||
int chasedist1;
|
||||
int chasedist2;
|
||||
|
||||
ai_handle_t ai; //JABot
|
||||
ai_handle_t *ai; //jabot092(2)
|
||||
qboolean is_swim; //AI_CategorizePosition
|
||||
qboolean is_step;
|
||||
qboolean is_ladder;
|
||||
qboolean was_swim;
|
||||
qboolean was_step;
|
||||
};
|
||||
|
||||
#define SPHERE_DEFENDER 0x0001
|
||||
|
|
|
@ -2052,7 +2052,7 @@ respawn(edict_t *self)
|
|||
if (deathmatch->value || coop->value)
|
||||
{
|
||||
//JABot[start]
|
||||
if (self->ai.is_bot){
|
||||
if (self->ai && self->ai->is_bot){
|
||||
BOT_Respawn (self);
|
||||
return;
|
||||
}
|
||||
|
@ -2395,7 +2395,7 @@ PutClientInServer(edict_t *ent)
|
|||
VectorCopy(ent->s.angles, client->v_angle);
|
||||
|
||||
//JABot[start]
|
||||
if( ent->ai.is_bot == true )
|
||||
if( ent->ai && ent->ai->is_bot )
|
||||
return;
|
||||
//JABot[end]
|
||||
|
||||
|
|
Loading…
Reference in a new issue