void FCajunMaster::TurnToAng (AActor *actor) { int maxturn = MAXTURN; if (actor->player->ReadyWeapon != NULL) { if (actor->player->ReadyWeapon->WeaponFlags & WIF_BOT_EXPLOSIVE) { if (actor->player->t_roam && !actor->player->missile) { //Keep angle that where when shot where decided. return; } } if(actor->player->enemy) if(!actor->player->dest) //happens when running after item in combat situations, or normal, prevents weak turns if(actor->player->ReadyWeapon->ProjectileType == NULL && !(actor->player->ReadyWeapon->WeaponFlags & WIF_MELEEWEAPON)) if(Check_LOS(actor, actor->player->enemy, SHOOTFOV+5*ANGLE_1)) maxturn = 3; } int distance = actor->player->angle - actor->angle; if (abs (distance) < OKAYRANGE && !actor->player->enemy) return; distance /= TURNSENS; if (abs (distance) > maxturn) distance = distance < 0 ? -maxturn : maxturn; actor->angle += distance; }
//MAKEME: Make this a smart decision AActor *DCajunMaster::Find_enemy (AActor *bot) { int count; fixed_t closest_dist, temp; //To target. AActor *target; angle_t vangle; AActor *observer; if (!deathmatch) { // [RH] Take advantage of the Heretic/Hexen code to be a little smarter return P_RoughMonsterSearch (bot, 20); } //Note: It's hard to ambush a bot who is not alone if (bot->player->allround || bot->player->mate) vangle = ANGLE_MAX; else vangle = ENEMY_SCAN_FOV; bot->player->allround = false; target = NULL; closest_dist = FIXED_MAX; if (bot_observer) observer = players[consoleplayer].mo; else observer = NULL; for (count = 0; count < MAXPLAYERS; count++) { player_t *client = &players[count]; if (playeringame[count] && !bot->IsTeammate (client->mo) && client->mo != observer && client->mo->health > 0 && bot != client->mo) { if (Check_LOS (bot, client->mo, vangle)) //Here's a strange one, when bot is standing still, the P_CheckSight within Check_LOS almost always returns false. tought it should be the same checksight as below but.. (below works) something must be f****n wierd screded up. //if(P_CheckSight( bot, players[count].mo)) { temp = P_AproxDistance (client->mo->x - bot->x, client->mo->y - bot->y); //Too dark? if (temp > DARK_DIST && client->mo->Sector->lightlevel < WHATS_DARK && bot->player->Powers & PW_INFRARED) continue; if (temp < closest_dist) { closest_dist = temp; target = client->mo; } } } } return target; }
//how the bot moves. //MAIN movement function. void DBot::ThinkForMove (ticcmd_t *cmd) { fixed_t dist; bool stuck; int r; stuck = false; dist = dest ? player->mo->AproxDistance(dest) : 0; if (missile && ((!missile->velx || !missile->vely) || !Check_LOS(missile, SHOOTFOV*3/2))) { sleft = !sleft; missile = NULL; //Probably ended its travel. } if (player->mo->pitch > 0) player->mo->pitch -= 80; else if (player->mo->pitch <= -60) player->mo->pitch += 80; //HOW TO MOVE: if (missile && (player->mo->AproxDistance(missile)<AVOID_DIST)) //try avoid missile got from P_Mobj.c thinking part. { Pitch (missile); angle = player->mo->AngleTo(missile); cmd->ucmd.sidemove = sleft ? -SIDERUN : SIDERUN; cmd->ucmd.forwardmove = -FORWARDRUN; //Back IS best. if ((player->mo->AproxDistance(oldx, oldy)<50000) && t_strafe<=0) { t_strafe = 5; sleft = !sleft; } //If able to see enemy while avoiding missile, still fire at enemy. if (enemy && Check_LOS (enemy, SHOOTFOV)) Dofire (cmd); //Order bot to fire current weapon } else if (enemy && P_CheckSight (player->mo, enemy, 0)) //Fight! { Pitch (enemy); //Check if it's more important to get an item than fight. if (dest && (dest->flags&MF_SPECIAL)) //Must be an item, that is close enough. { #define is(x) dest->IsKindOf (PClass::FindClass (#x)) if ( ( (player->mo->health < skill.isp && (is (Medikit) || is (Stimpack) || is (Soulsphere) || is (Megasphere) || is (CrystalVial) ) ) || ( is (Invulnerability) || is (Invisibility) || is (Megasphere) ) || dist < (GETINCOMBAT/4) || (player->ReadyWeapon == NULL || player->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON) ) && (dist < GETINCOMBAT || (player->ReadyWeapon == NULL || player->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON)) && Reachable (dest)) #undef is { goto roam; //Pick it up, no matter the situation. All bonuses are nice close up. } } dest = NULL; //To let bot turn right if (player->ReadyWeapon != NULL && !(player->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON)) player->mo->flags &= ~MF_DROPOFF; //Don't jump off any ledges when fighting. if (!(enemy->flags3 & MF3_ISMONSTER)) t_fight = AFTERTICS; if (t_strafe <= 0 && (player->mo->AproxDistance(oldx, oldy)<50000 || ((pr_botmove()%30)==10)) ) { stuck = true; t_strafe = 5; sleft = !sleft; } angle = player->mo->AngleTo(enemy); if (player->ReadyWeapon == NULL || player->mo->AproxDistance(enemy) > player->ReadyWeapon->MoveCombatDist) { // If a monster, use lower speed (just for cooler apperance while strafing down doomed monster) cmd->ucmd.forwardmove = (enemy->flags3 & MF3_ISMONSTER) ? FORWARDWALK : FORWARDRUN; } else if (!stuck) //Too close, so move away. { // If a monster, use lower speed (just for cooler apperance while strafing down doomed monster) cmd->ucmd.forwardmove = (enemy->flags3 & MF3_ISMONSTER) ? -FORWARDWALK : -FORWARDRUN; } //Strafing. if (enemy->flags3 & MF3_ISMONSTER) //It's just a monster so take it down cool. { cmd->ucmd.sidemove = sleft ? -SIDEWALK : SIDEWALK; } else { cmd->ucmd.sidemove = sleft ? -SIDERUN : SIDERUN; } Dofire (cmd); //Order bot to fire current weapon } else if (mate && !enemy && (!dest || dest==mate)) //Follow mate move. { fixed_t matedist; Pitch (mate); if (!Reachable (mate)) { if (mate == dest && pr_botmove.Random() < 32) { // [RH] If the mate is the dest, pick a new dest sometimes dest = NULL; } goto roam; } angle = player->mo->AngleTo(mate); matedist = player->mo->AproxDistance(mate); if (matedist > (FRIEND_DIST*2)) cmd->ucmd.forwardmove = FORWARDRUN; else if (matedist > FRIEND_DIST) cmd->ucmd.forwardmove = FORWARDWALK; //Walk, when starting to get close. else if (matedist < FRIEND_DIST-(FRIEND_DIST/3)) //Got too close, so move away. cmd->ucmd.forwardmove = -FORWARDWALK; } else //Roam after something. { first_shot = true; ///// roam: ///// if (enemy && Check_LOS (enemy, SHOOTFOV*3/2)) //If able to see enemy while avoiding missile , still fire at it. Dofire (cmd); //Order bot to fire current weapon if (dest && !(dest->flags&MF_SPECIAL) && dest->health < 0) { //Roaming after something dead. dest = NULL; } if (dest == NULL) { if (t_fight && enemy) //Enemy/bot has jumped around corner. So what to do? { if (enemy->player) { if (((enemy->player->ReadyWeapon != NULL && enemy->player->ReadyWeapon->WeaponFlags & WIF_BOT_EXPLOSIVE) || (pr_botmove()%100)>skill.isp) && player->ReadyWeapon != NULL && !(player->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON)) dest = enemy;//Dont let enemy kill the bot by supressive fire. So charge enemy. else //hide while t_fight, but keep view at enemy. angle = player->mo->AngleTo(enemy); } //Just a monster, so kill it. else dest = enemy; //VerifFavoritWeapon(player); //Dont know why here.., but it must be here, i know the reason, but not why at this spot, uh. } else //Choose a distant target. to get things going. { r = pr_botmove(); if (r < 128) { TThinkerIterator<AInventory> it (STAT_INVENTORY, bglobal.firstthing); AInventory *item = it.Next(); if (item != NULL || (item = it.Next()) != NULL) { r &= 63; // Only scan up to 64 entries at a time while (r) { --r; item = it.Next(); } if (item == NULL) { item = it.Next(); } bglobal.firstthing = item; dest = item; } } else if (mate && (r < 179 || P_CheckSight(player->mo, mate))) { dest = mate; } else if ((playeringame[(r&(MAXPLAYERS-1))]) && players[(r&(MAXPLAYERS-1))].mo->health > 0) { dest = players[(r&(MAXPLAYERS-1))].mo; } } if (dest) { t_roam = MAXROAM; } } if (dest) { //Bot has a target so roam after it. Roam (cmd); } } //End of movement main part. if (!t_roam && dest) { prev = dest; dest = NULL; } if (t_fight<(AFTERTICS/2)) player->mo->flags |= MF_DROPOFF; oldx = player->mo->X(); oldy = player->mo->Y(); }
//------------------------------------- //Bot_Dofire() //------------------------------------- //The bot will check if it's time to fire //and do so if that is the case. void DCajunMaster::Dofire (AActor *actor, ticcmd_t *cmd) { bool no_fire; //used to prevent bot from pumping rockets into nearby walls. int aiming_penalty=0; //For shooting at shading target, if screen is red, MAKEME: When screen red. int aiming_value; //The final aiming value. fixed_t dist; angle_t an; int m; static bool inc[MAXPLAYERS]; AActor *enemy = actor->player->enemy; if (!enemy || !(enemy->flags & MF_SHOOTABLE) || enemy->health <= 0) return; if (actor->player->ReadyWeapon == NULL) return; if (actor->player->damagecount > actor->player->skill.isp) { actor->player->first_shot = true; return; } //Reaction skill thing. if (actor->player->first_shot && !(actor->player->ReadyWeapon->WeaponFlags & WIF_BOT_REACTION_SKILL_THING)) { actor->player->t_react = (100-actor->player->skill.reaction+1)/((pr_botdofire()%3)+3); } actor->player->first_shot = false; if (actor->player->t_react) return; //MAKEME: Decrease the rocket suicides even more. no_fire = true; //actor->player->angle = R_PointToAngle2(actor->x, actor->y, actor->player->enemy->x, actor->player->enemy->y); //Distance to enemy. dist = P_AproxDistance ((actor->x + actor->momx) - (enemy->x + enemy->momx), (actor->y + actor->momy) - (enemy->y + enemy->momy)); //FIRE EACH TYPE OF WEAPON DIFFERENT: Here should all the different weapons go. if (actor->player->ReadyWeapon->WeaponFlags & WIF_BOT_MELEE) { if ((actor->player->ReadyWeapon->ProjectileType != NULL)) { if (actor->player->ReadyWeapon->CheckAmmo (AWeapon::PrimaryFire, false, true)) { // This weapon can fire a projectile and has enough ammo to do so goto shootmissile; } else if (!(actor->player->ReadyWeapon->WeaponFlags & WIF_AMMO_OPTIONAL)) { // Ammo is required, so don't shoot. This is for weapons that shoot // missiles that die at close range, such as the powered-up Phoneix Rod. return; } } else { //*4 is for atmosphere, the chainsaws sounding and all.. no_fire = (dist > (MELEERANGE*4)); } } else if (actor->player->ReadyWeapon->WeaponFlags & WIF_BOT_BFG) { //MAKEME: This should be smarter. if ((pr_botdofire()%200)<=actor->player->skill.reaction) if(Check_LOS(actor, actor->player->enemy, SHOOTFOV)) no_fire = false; } else if (actor->player->ReadyWeapon->ProjectileType != NULL) { if (actor->player->ReadyWeapon->WeaponFlags & WIF_BOT_EXPLOSIVE) { //Special rules for RL an = FireRox (actor, enemy, cmd); if(an) { actor->player->angle = an; //have to be somewhat precise. to avoid suicide. if (abs (actor->player->angle - actor->angle) < 12*ANGLE_1) { actor->player->t_rocket = 9; no_fire = false; } } } // prediction aiming shootmissile: dist = P_AproxDistance (actor->x - enemy->x, actor->y - enemy->y); m = dist / GetDefaultByType (actor->player->ReadyWeapon->ProjectileType)->Speed; SetBodyAt (enemy->x + enemy->momx*m*2, enemy->y + enemy->momy*m*2, enemy->z, 1); actor->player->angle = R_PointToAngle2 (actor->x, actor->y, body1->x, body1->y); if (Check_LOS (actor, enemy, SHOOTFOV)) no_fire = false; } else { //Other weapons, mostly instant hit stuff. actor->player->angle = R_PointToAngle2 (actor->x, actor->y, enemy->x, enemy->y); aiming_penalty = 0; if (enemy->flags & MF_SHADOW) aiming_penalty += (pr_botdofire()%25)+10; if (enemy->Sector->lightlevel<WHATS_DARK/* && !(actor->player->powers & PW_INFRARED)*/) aiming_penalty += pr_botdofire()%40;//Dark if (actor->player->damagecount) aiming_penalty += actor->player->damagecount; //Blood in face makes it hard to aim aiming_value = actor->player->skill.aiming - aiming_penalty; if (aiming_value <= 0) aiming_value = 1; m = ((SHOOTFOV/2)-(aiming_value*SHOOTFOV/200)); //Higher skill is more accurate if (m <= 0) m = 1; //Prevents lock. if (m) { if (inc[actor->id]) actor->player->angle += m; else actor->player->angle -= m; } if (abs (actor->player->angle - actor->angle) < 4*ANGLE_1) { inc[actor->id] = !inc[actor->id]; } if (Check_LOS (actor, enemy, (SHOOTFOV/2))) no_fire = false; } if (!no_fire) //If going to fire weapon { cmd->ucmd.buttons |= BT_ATTACK; } //Prevents bot from jerking, when firing automatic things with low skill. //actor->angle = R_PointToAngle2(actor->x, actor->y, actor->player->enemy->x, actor->player->enemy->y); }