DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_Refire) { PARAM_ACTION_PROLOGUE; PARAM_BOOL_OPT(ignoremissile) { ignoremissile = false; } if (self->target == NULL || self->target->health <= 0) { if (self->MissileState && pr_m_refire() < 160) { // Look for a new target most of the time if (P_LookForPlayers (self, true, NULL) && P_CheckMissileRange (self)) { // Found somebody new and in range, so don't stop shooting return 0; } } self->SetState (self->state + 1); return 0; } if (((ignoremissile || self->MissileState == NULL) && !self->CheckMeleeRange ()) || !P_CheckSight (self, self->target) || pr_m_refire() < 4) // Small chance of stopping even when target not dead { self->SetState (self->state + 1); } return 0; }
DEFINE_ACTION_FUNCTION(AActor, A_CPosRefire) { // keep firing unless target got out of sight A_FaceTarget (self); // [BC] Client chaingunners continue to fire until told by the server to stop. if (( NETWORK_GetState( ) == NETSTATE_CLIENT ) || ( CLIENTDEMO_IsPlaying( ))) { return; } if (pr_cposrefire() < 40) return; if (!self->target || P_HitFriend (self) || self->target->health <= 0 || !P_CheckSight (self, self->target, SF_SEEPASTBLOCKEVERYTHING|SF_SEEPASTSHOOTABLELINES)) { // [BC] If we're the server, tell clients to update this thing's state. if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVERCOMMANDS_SetThingState( self, STATE_SEE ); self->SetState (self->SeeState); } }
// // A_SpidRefire // // Spider Mastermind line-of-sight checking. // void A_SpidRefire(actionargs_t *actionargs) { Mobj *actor = actionargs->actor; // keep firing unless target got out of sight A_FaceTarget(actionargs); // killough 12/98: Stop firing if a friend has gotten in the way if(actor->flags & MF_FRIEND && P_HitFriend(actor)) { P_SetMobjState(actor, actor->info->seestate); return; } if(P_Random(pr_spidrefire) < 10) return; // killough 11/98: prevent refiring on friends continuously if(!actor->target || actor->target->health <= 0 || actor->flags & actor->target->flags & MF_FRIEND || !P_CheckSight(actor, actor->target)) { P_SetMobjState(actor, actor->info->seestate); } }
DEFINE_ACTION_FUNCTION(AActor, A_TurretLook) { AActor *target; if (self->flags5 & MF5_INCONVERSATION) return; self->threshold = 0; target = self->LastHeard; if (target != NULL && target->health > 0 && target->flags & MF_SHOOTABLE && (self->flags & MF_FRIENDLY) != (target->flags & MF_FRIENDLY)) { self->target = target; if ((self->flags & MF_AMBUSH) && !P_CheckSight (self, target)) { return; } if (self->SeeSound != 0) { S_Sound (self, CHAN_VOICE, self->SeeSound, 1, ATTN_NORM); } self->LastHeard = NULL; self->threshold = 10; self->SetState (self->SeeState); } }
void DBot::Set_enemy () { AActor *oldenemy; if (enemy && enemy->health > 0 && P_CheckSight (player->mo, enemy)) { oldenemy = enemy; } else { oldenemy = NULL; } // [RH] Don't even bother looking for a different enemy if this is not deathmatch // and we already have an existing enemy. if (deathmatch || !enemy) { allround = !!enemy; enemy = Find_enemy(); if (!enemy) enemy = oldenemy; //Try go for last (it will be NULL if there wasn't anyone) } //Verify that that enemy is really something alive that bot can kill. if (enemy && ((enemy->health < 0 || !(enemy->flags&MF_SHOOTABLE)) || player->mo->IsFriend(enemy))) enemy = NULL; }
bool InquisitorCheckDistance (AActor *self) { if (self->reactiontime == 0 && P_CheckSight (self, self->target)) { return P_AproxDistance (self->x - self->target->x, self->y - self->target->y) < 264*FRACUNIT; } return false; }
bool Sys_1ed64 (AActor *self) { if (P_CheckSight (self, self->target) && self->reactiontime == 0) { return P_AproxDistance (self->x - self->target->x, self->y - self->target->y) < 264*FRACUNIT; } return false; }
static bool CrusaderCheckRange (AActor *self) { if (self->reactiontime == 0 && P_CheckSight (self, self->target)) { return self->AproxDistance (self->target) < 264*FRACUNIT; } return false; }
angle_t DBot::FireRox (AActor *enemy, ticcmd_t *cmd) { fixed_t dist; angle_t ang; AActor *actor; int m; bglobal.SetBodyAt (player->mo->X() + FixedMul(player->mo->velx, 5*FRACUNIT), player->mo->Y() + FixedMul(player->mo->vely, 5*FRACUNIT), player->mo->Z() + (player->mo->height / 2), 2); actor = bglobal.body2; dist = actor->AproxDistance (enemy); if (dist < SAFE_SELF_MISDIST) return 0; //Predict. m = (((dist+1)/FRACUNIT) / GetDefaultByName("Rocket")->Speed); bglobal.SetBodyAt (enemy->X() + FixedMul(enemy->velx, (m+2*FRACUNIT)), enemy->Y() + FixedMul(enemy->vely, (m+2*FRACUNIT)), ONFLOORZ, 1); //try the predicted location if (P_CheckSight (actor, bglobal.body1, SF_IGNOREVISIBILITY)) //See the predicted location, so give a test missile { FCheckPosition tm; if (bglobal.SafeCheckPosition (player->mo, actor->X(), actor->Y(), tm)) { if (bglobal.FakeFire (actor, bglobal.body1, cmd) >= SAFE_SELF_MISDIST) { ang = actor->AngleTo(bglobal.body1); return ang; } } } //Try fire straight. if (P_CheckSight (actor, enemy, 0)) { if (bglobal.FakeFire (player->mo, enemy, cmd) >= SAFE_SELF_MISDIST) { ang = player->mo->AngleTo(enemy); return ang; } } return 0; }
bool InquisitorCheckDistance (AActor *self) { if (self->reactiontime == 0 && P_CheckSight (self, self->target)) { return self->Distance2D (self->target) < 264.; } return false; }
angle_t DCajunMaster::FireRox (AActor *bot, AActor *enemy, ticcmd_t *cmd) { fixed_t dist; angle_t ang; AActor *actor; int m; SetBodyAt (bot->x + FixedMul(bot->momx, 5*FRACUNIT), bot->y + FixedMul(bot->momy, 5*FRACUNIT), bot->z + (bot->height / 2), 2); actor = bglobal.body2; dist = P_AproxDistance (actor->x-enemy->x, actor->y-enemy->y); if (dist < SAFE_SELF_MISDIST) return 0; //Predict. m = (((dist+1)/FRACUNIT) / GetDefault<ARocket>()->Speed); SetBodyAt (enemy->x + FixedMul (enemy->momx, (m+2*FRACUNIT)), enemy->y + FixedMul(enemy->momy, (m+2*FRACUNIT)), ONFLOORZ, 1); dist = P_AproxDistance(actor->x-bglobal.body1->x, actor->y-bglobal.body1->y); //try the predicted location if (P_CheckSight (actor, bglobal.body1, 1)) //See the predicted location, so give a test missile { if (SafeCheckPosition (bot, actor->x, actor->y)) { if (FakeFire (actor, bglobal.body1, cmd) >= SAFE_SELF_MISDIST) { ang = R_PointToAngle2 (actor->x, actor->y, bglobal.body1->x, bglobal.body1->y); return ang; } } } //Try fire straight. if (P_CheckSight (actor, enemy, 0)) { if (FakeFire (bot, enemy, cmd) >= SAFE_SELF_MISDIST) { ang = R_PointToAngle2(bot->x, bot->y, enemy->x, enemy->y); return ang; } } return 0; }
DEFINE_ACTION_FUNCTION(AActor, A_CrusaderRefire) { if (self->target == NULL || self->target->health <= 0 || !P_CheckSight (self, self->target)) { self->SetState (self->SeeState); } }
//doesnt check LOS, checks visibility with a set view angle. //B_Checksight checks LOS (straight line) //---------------------------------------------------------------------- //Check if mo1 has free line to mo2 //and if mo2 is within mo1 viewangle (vangle) given with normal degrees. //if these conditions are true, the function returns true. //GOOD TO KNOW is that the player's view angle //in doom is 90 degrees infront. bool DCajunMaster::Check_LOS (AActor *from, AActor *to, angle_t vangle) { if (!P_CheckSight (from, to, 2)) return false; // out of sight if (vangle == ANGLE_MAX) return true; if (vangle == 0) return false; //Looker seems to be blind. return abs (R_PointToAngle2 (from->x, from->y, to->x, to->y) - from->angle) <= vangle/2; }
//doesnt check LOS, checks visibility with a set view angle. //B_Checksight checks LOS (straight line) //---------------------------------------------------------------------- //Check if mo1 has free line to mo2 //and if mo2 is within mo1 viewangle (vangle) given with normal degrees. //if these conditions are true, the function returns true. //GOOD TO KNOW is that the player's view angle //in doom is 90 degrees infront. bool DBot::Check_LOS (AActor *to, angle_t vangle) { if (!P_CheckSight (player->mo, to, SF_SEEPASTBLOCKEVERYTHING)) return false; // out of sight if (vangle == ANGLE_MAX) return true; if (vangle == 0) return false; //Looker seems to be blind. return absangle(player->mo->AngleTo(to) - player->mo->angle) <= vangle/2; }
DEFINE_ACTION_FUNCTION(AActor, A_CrusaderRefire) { PARAM_ACTION_PROLOGUE; if (self->target == NULL || self->target->health <= 0 || !P_CheckSight (self, self->target)) { self->SetState (self->SeeState); } return 0; }
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_VileAttack) { ACTION_PARAM_START(7); ACTION_PARAM_SOUND(snd,0); ACTION_PARAM_INT(dmg,1); ACTION_PARAM_INT(blastdmg,2); ACTION_PARAM_INT(blastrad,3); ACTION_PARAM_FIXED(thrust,4); ACTION_PARAM_NAME(dmgtype,5); ACTION_PARAM_INT(flags,6); AActor *fire, *target; angle_t an; if (NULL == (target = self->target)) return; A_FaceTarget (self); if (!P_CheckSight (self, target, 0) ) return; S_Sound (self, CHAN_WEAPON, snd, 1, ATTN_NORM); int newdam; if (flags & VAF_DMGTYPEAPPLYTODIRECT) newdam = P_DamageMobj (target, self, self, dmg, dmgtype); else newdam = P_DamageMobj (target, self, self, dmg, NAME_None); P_TraceBleed (newdam > 0 ? newdam : dmg, target); an = self->angle >> ANGLETOFINESHIFT; fire = self->tracer; if (fire != NULL) { // move the fire between the vile and the player fire->SetOrigin (target->x - FixedMul (24*FRACUNIT, finecosine[an]), target->y - FixedMul (24*FRACUNIT, finesine[an]), target->z); P_RadiusAttack (fire, self, blastdmg, blastrad, dmgtype, 0); } if (!(target->flags7 & MF7_DONTTHRUST)) target->velz = Scale(thrust, 1000, target->Mass); }
void A_Fire(AActor *self, int height) { AActor *dest; dest = self->tracer; if (dest == NULL || self->target == NULL) return; // don't move it if the vile lost sight if (!P_CheckSight (self->target, dest, 0) ) return; fixedvec3 newpos = dest->Vec3Angle(24 * FRACUNIT, dest->angle, height); self->SetOrigin(newpos, true); }
// // P_CheckMissileRange // boolean P_CheckMissileRange (mobj_t* actor) { fixed_t dist; if (! P_CheckSight (actor, actor->target) ) return false; if ( actor->flags & MF_JUSTHIT ) { // the target just hit the enemy, // so fight back! actor->flags &= ~MF_JUSTHIT; return true; } if (actor->reactiontime) return false; // do not attack yet // OPTIMIZE: get this from a global checksight dist = P_AproxDistance ( actor->x-actor->target->x, actor->y-actor->target->y) - 64*FRACUNIT; if (!actor->info->meleestate) dist -= 128*FRACUNIT; // no melee attack, so fire more dist >>= 16; if (actor->type == MT_VILE) { if (dist > 14*64) return false; // too far away } if (actor->type == MT_UNDEAD) { if (dist < 196) return false; // close for fist attack dist >>= 1; } if (actor->type == MT_CYBORG || actor->type == MT_SPIDER || actor->type == MT_SKULL) { dist >>= 1; }
DEFINE_ACTION_FUNCTION(AActor, A_CPosRefire) { // keep firing unless target got out of sight A_FaceTarget (self); if (pr_cposrefire() < 40) return; if (!self->target || P_HitFriend (self) || self->target->health <= 0 || !P_CheckSight (self, self->target, SF_SEEPASTBLOCKEVERYTHING|SF_SEEPASTSHOOTABLELINES)) { self->SetState (self->SeeState); } }
DEFINE_ACTION_FUNCTION(AActor, A_PotteryCheck) { int i; for(i = 0; i < MAXPLAYERS; i++) { if (playeringame[i]) { AActor *pmo = players[i].mo; if (P_CheckSight (self, pmo) && (abs (R_PointToAngle2 (pmo->x, pmo->y, self->x, self->y) - pmo->angle) <= ANGLE_45)) { // Previous state (pottery bit waiting state) self->SetState (self->state - 1); return; } } } }
// // P_CheckMeleeRange // boolean P_CheckMeleeRange (mobj_t* actor) { mobj_t* pl; fixed_t dist; if (!actor->target) return false; pl = actor->target; dist = P_AproxDistance (pl->x-actor->x, pl->y-actor->y); if (dist >= MELEERANGE-20*FRACUNIT+pl->info->radius) return false; if (! P_CheckSight (actor, actor->target) ) return false; return true; }
void A_Fire(AActor *self, int height) { AActor *dest; angle_t an; dest = self->tracer; if (dest == NULL || self->target == NULL) return; // don't move it if the vile lost sight if (!P_CheckSight (self->target, dest, 0) ) return; an = dest->angle >> ANGLETOFINESHIFT; self->SetOrigin (dest->x + FixedMul (24*FRACUNIT, finecosine[an]), dest->y + FixedMul (24*FRACUNIT, finesine[an]), dest->z + height); }
DEFINE_ACTION_FUNCTION(AActor, A_SentinelRefire) { PARAM_ACTION_PROLOGUE; A_FaceTarget (self); if (pr_sentinelrefire() >= 30) { if (self->target == NULL || self->target->health <= 0 || !P_CheckSight (self, self->target, SF_SEEPASTBLOCKEVERYTHING|SF_SEEPASTSHOOTABLELINES) || P_HitFriend(self) || (self->MissileState == NULL && !self->CheckMeleeRange()) || pr_sentinelrefire() < 40) { self->SetState (self->SeeState); } } return 0; }
// // ACS_funcCheckSight // static void ACS_funcCheckSight(ACS_FUNCARG) { int32_t tid1 = args[0]; int32_t tid2 = args[1]; Mobj *mo1 = NULL; Mobj *mo2 = NULL; while((mo1 = P_FindMobjFromTID(tid1, mo1, thread->trigger))) { while((mo2 = P_FindMobjFromTID(tid2, mo2, thread->trigger))) { if(P_CheckSight(mo1, mo2)) { *retn++ = 1; return; } } } *retn++ = 0; }
DEFINE_ACTION_FUNCTION(AActor, A_M_Refire) { // [BC] Let the server do this. if (( NETWORK_GetState( ) == NETSTATE_CLIENT ) || ( CLIENTDEMO_IsPlaying( ))) { return; } if (self->target == NULL || self->target->health <= 0) { if (self->MissileState && pr_m_refire() < 160) { // Look for a new target most of the time if (P_LookForPlayers (self, true) && P_CheckMissileRange (self)) { // Found somebody new and in range, so don't stop shooting return; } } // [BC] Update the thing's state. if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVERCOMMANDS_SetThingFrame( self, self->state + 1 ); self->SetState (self->state + 1); return; } if ((self->MissileState == NULL && !self->CheckMeleeRange ()) || !P_CheckSight (self, self->target) || pr_m_refire() < 4) // Small chance of stopping even when target not dead { // [BC] Update the thing's state. if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVERCOMMANDS_SetThingFrame( self, self->state + 1 ); self->SetState (self->state + 1); } }
bool P_Thing_CheckProximity(AActor *self, PClass *classname, double distance, int count, int flags, int ptr) { AActor *ref = COPY_AAPTR(self, ptr); // We need these to check out. if (!ref || !classname || distance <= 0) return false; int counter = 0; bool result = false; double closer = distance, farther = 0, current = distance; const bool ptrWillChange = !!(flags & (CPXF_SETTARGET | CPXF_SETMASTER | CPXF_SETTRACER)); const bool ptrDistPref = !!(flags & (CPXF_CLOSEST | CPXF_FARTHEST)); TThinkerIterator<AActor> it; AActor *mo, *dist = nullptr; // [MC] Process of elimination, I think, will get through this as quickly and // efficiently as possible. while ((mo = it.Next())) { if (mo == ref) //Don't count self. continue; // no unmorphed versions of currently morphed players. if (mo->flags & MF_UNMORPHED) continue; // Check inheritance for the classname. Taken partly from CheckClass DECORATE function. if (flags & CPXF_ANCESTOR) { if (!(mo->IsKindOf(classname))) continue; } // Otherwise, just check for the regular class name. else if (classname != mo->GetClass()) continue; // [MC]Make sure it's in range and respect the desire for Z or not. The function forces it to use // Z later for ensuring CLOSEST and FARTHEST flags are respected perfectly. // Ripped from sphere checking in A_RadiusGive (along with a number of things). if ((ref->Distance2D(mo) < distance && ((flags & CPXF_NOZ) || ((ref->Z() > mo->Z() && ref->Z() - mo->Top() < distance) || (ref->Z() <= mo->Z() && mo->Z() - ref->Top() < distance))))) { if ((flags & CPXF_CHECKSIGHT) && !(P_CheckSight(mo, ref, SF_IGNOREVISIBILITY | SF_IGNOREWATERBOUNDARY))) continue; if (ptrWillChange) { current = ref->Distance2D(mo); if ((flags & CPXF_CLOSEST) && (current < closer)) { dist = mo; closer = current; // This actor's closer. Set the new standard. } else if ((flags & CPXF_FARTHEST) && (current > farther)) { dist = mo; farther = current; } else if (!dist) dist = mo; // Just get the first one and call it quits if there's nothing selected. } if (mo->flags6 & MF6_KILLED) { if (!(flags & (CPXF_COUNTDEAD | CPXF_DEADONLY))) continue; counter++; } else { if (flags & CPXF_DEADONLY) continue; counter++; } // Abort if the number of matching classes nearby is greater, we have obviously succeeded in our goal. if (counter > count) { result = (flags & (CPXF_LESSOREQUAL | CPXF_EXACT)) ? false : true; // However, if we have one SET* flag and either the closest or farthest flags, keep the function going. if (ptrWillChange && ptrDistPref) continue; else break; } } } if (ptrWillChange && dist != 0) { if (flags & CPXF_SETONPTR) { if (flags & CPXF_SETTARGET) ref->target = dist; if (flags & CPXF_SETMASTER) ref->master = dist; if (flags & CPXF_SETTRACER) ref->tracer = dist; } else { if (flags & CPXF_SETTARGET) self->target = dist; if (flags & CPXF_SETMASTER) self->master = dist; if (flags & CPXF_SETTRACER) self->tracer = dist; } } if (counter == count) result = true; else if (counter < count) result = !!((flags & CPXF_LESSOREQUAL) && !(flags & CPXF_EXACT)); return result; }
//This function is called every //tick (for each bot) to set //the mate (teammate coop mate). AActor *DBot::Choose_Mate () { int count; fixed_t closest_dist, test; AActor *target; AActor *observer; //is mate alive? if (mate) { if (mate->health <= 0) mate = NULL; else last_mate = mate; } if (mate) //Still is.. return mate; //Check old_mates status. if (last_mate) if (last_mate->health <= 0) last_mate = NULL; target = NULL; closest_dist = FIXED_MAX; if (bot_observer) observer = players[consoleplayer].mo; else observer = NULL; //Check for player friends for (count = 0; count < MAXPLAYERS; count++) { player_t *client = &players[count]; if (playeringame[count] && client->mo && player->mo != client->mo && (player->mo->IsTeammate (client->mo) || !deathmatch) && client->mo->health > 0 && client->mo != observer && ((player->mo->health/2) <= client->mo->health || !deathmatch) && !bglobal.IsLeader(client)) //taken? { if (P_CheckSight (player->mo, client->mo, SF_IGNOREVISIBILITY)) { test = client->mo->AproxDistance(player->mo); if (test < closest_dist) { closest_dist = test; target = client->mo; } } } } /* //Make a introducing to mate. if(target && target!=last_mate) { if((P_Random()%(200*bglobal.botnum))<3) { chat = c_teamup; if(target->bot) strcpy(c_target, botsingame[target->bot_id]); else if(target->player) strcpy(c_target, player_names[target->play_id]); } } */ 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(); }
//This function is called every //tick (for each bot) to set //the mate (teammate coop mate). AActor *DCajunMaster::Choose_Mate (AActor *bot) { int count; int count2; fixed_t closest_dist, test; AActor *target; AActor *observer; bool p_leader[MAXPLAYERS]; //is mate alive? if (bot->player->mate) { if (bot->player->mate->health <= 0) bot->player->mate = NULL; else bot->player->last_mate = bot->player->mate; } if (bot->player->mate) //Still is.. return bot->player->mate; //Check old_mates status. if (bot->player->last_mate) if (bot->player->last_mate->health <= 0) bot->player->last_mate = NULL; for (count = 0; count < MAXPLAYERS; count++) { if (!playeringame[count]) continue; p_leader[count] = false; for (count2 = 0; count2 < MAXPLAYERS; count2++) { if (players[count].isbot && players[count2].mate == players[count].mo) { p_leader[count] = true; break; } } } target = NULL; closest_dist = FIXED_MAX; if (bot_observer) observer = players[consoleplayer].mo; else observer = NULL; //Check for player friends for (count = 0; count < MAXPLAYERS; count++) { player_t *client = &players[count]; if (playeringame[count] && client->mo && bot != client->mo && (bot->IsTeammate (client->mo) || !deathmatch) && client->mo->health > 0 && client->mo != observer && ((bot->health/2) <= client->mo->health || !deathmatch) && !p_leader[count]) //taken? { if (P_CheckSight (bot, client->mo, 1)) { test = P_AproxDistance (client->mo->x - bot->x, client->mo->y - bot->y); if (test < closest_dist) { closest_dist = test; target = client->mo; } } } } /* //Make a introducing to mate. if(target && target!=bot->player->last_mate) { if((P_Random()%(200*bglobal.botnum))<3) { bot->player->chat = c_teamup; if(target->bot) strcpy(bot->player->c_target, botsingame[target->bot_id]); else if(target->player) strcpy(bot->player->c_target, player_names[target->play_id]); } } */ return target; }
dd_bool Mobj_LookForPlayers(mobj_t *mo, dd_bool allAround) { int const playerCount = P_CountPlayersInGame(); // Nobody to target? if(!playerCount) return false; int const from = mo->lastLook % MAXPLAYERS; int const to = (from + MAXPLAYERS - 1) % MAXPLAYERS; int cand = from; int tries = 0; bool foundTarget = false; for(; cand != to; cand = (cand < (MAXPLAYERS - 1)? cand + 1 : 0)) { player_t *player = players + cand; // Is player in the game? if(!player->plr->inGame) continue; mobj_t *plrmo = player->plr->mo; if(!plrmo) continue; // Do not target camera players. if(P_MobjIsCamera(plrmo)) continue; // Only look ahead a fixed number of times. if(tries++ == 2) break; // Do not target dead players. if(player->health <= 0) continue; // Within sight? if(!P_CheckSight(mo, plrmo)) continue; if(!allAround) { angle_t an = M_PointToAngle2(mo->origin, plrmo->origin); an -= mo->angle; if(an > ANG90 && an < ANG270) { // If real close, react anyway. coord_t dist = M_ApproxDistance(plrmo->origin[VX] - mo->origin[VX], plrmo->origin[VY] - mo->origin[VY]); // Behind us? if(dist > MELEERANGE) continue; } } #if __JHERETIC__ || __JHEXEN__ // If player is invisible we may not detect if too far or randomly. if(plrmo->flags & MF_SHADOW) { if((M_ApproxDistance(plrmo->origin[VX] - mo->origin[VX], plrmo->origin[VY] - mo->origin[VY]) > 2 * MELEERANGE) && M_ApproxDistance(plrmo->mom[MX], plrmo->mom[MY]) < 5) { // Too far; can't detect. continue; } // Randomly overlook the player regardless. if(P_Random() < 225) continue; } #endif #if __JHEXEN__ // Minotaurs do not target their master. if(mo->type == MT_MINOTAUR && mo->tracer && mo->tracer->player == player) continue; #endif // Found our quarry. mo->target = plrmo; foundTarget = true; } // Start looking from here next time. mo->lastLook = cand; return foundTarget; }