void Vehicle::ApplyAllImmunities() { // This couldn't be done in DB, because some spells have MECHANIC_NONE // Vehicles should be immune on Knockback ... _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true); _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK_DEST, true); // Mechanical units & vehicles ( which are not Bosses, they have own immunities in DB ) should be also immune on healing ( exceptions in switch below ) if (_me->ToCreature() && _me->ToCreature()->GetCreatureTemplate()->type == CREATURE_TYPE_MECHANICAL && !_me->ToCreature()->isWorldBoss()) { // Heal & dispel ... _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_HEAL, true); _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_HEAL_PCT, true); _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_DISPEL, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_PERIODIC_HEAL, true); // ... Shield & Immunity grant spells ... _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_SCHOOL_IMMUNITY, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_UNATTACKABLE, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_SCHOOL_ABSORB, true); _me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SHIELD, true); _me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_IMMUNE_SHIELD, true); // ... Resistance, Split damage, Change stats ... _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_DAMAGE_SHIELD, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_SPLIT_DAMAGE_PCT, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_RESISTANCE, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_STAT, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, true); } // If vehicle flag for fixed position set (cannons), or if the following hardcoded units, then set state rooted // 30236 | Argent Cannon // 39759 | Tankbuster Cannon if ((GetVehicleInfo()->m_flags & VEHICLE_FLAG_FIXED_POSITION) || GetBase()->GetEntry() == 30236 || GetBase()->GetEntry() == 39759) _me->SetControlled(true, UNIT_STATE_ROOT); // Different immunities for vehicles goes below switch (GetVehicleInfo()->m_ID) { // code below prevents a bug with movable cannons case 160: // Strand of the Ancients case 244: // Wintergrasp case 510: // Isle of Conquest case 452: // Isle of Conquest case 543: // Isle of Conquest _me->SetControlled(true, UNIT_STATE_ROOT); // why we need to apply this? we can simple add immunities to slow mechanic in DB _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_DECREASE_SPEED, true); break; default: break; } }
PSpawnedVehicle* PVehicles::SpawnVehicle( u32 nVehicleId, u32 nLocation, PVhcCoordinates const* nVhcPos ) { PSpawnedVehicle* newVhc = NULL; PWorld* cWorld; PVehicleInformation nVhcInfo; if (( nLocation != PWorlds::mNcSubwayWorldId ) && IsValidVehicle( nVehicleId ) && !IsSpawned( nVehicleId ) ) { cWorld = Worlds->LeaseWorld( nLocation ); if ( cWorld && GetVehicleInfo( nVehicleId, &nVhcInfo ) ) { newVhc = cWorld->GetSpawnedVehicules()->SpawnVehicle( &nVhcInfo, nVhcPos ); if ( newVhc ) { if ( !RegisterSpawnedVehicle( newVhc ) ) { Console->Print( RED, BLACK, "[Error] PVehicles::SpawnVehicle : Could not register spawned vhc" ); } if( gDevDebug ) Console->Print( "%d Spawned vhc %d (local 0x%04x) type %d (requested: %d)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), newVhc->GetVehicleId(), newVhc->GetLocalId(), newVhc->GetInformation().GetVehicleType(), nVhcInfo.GetVehicleType() ); } else Console->Print( RED, BLACK, "[Error] PVehicles::SpawnVehicle : Could not create vhc" ); } Worlds->ReleaseWorld( nLocation ); } return newVhc; }
PVhcInfoList* PVehicles::GetCharVehicles( u32 nCharId, u16 nMaxCount, u16 nStartIndex ) { PVhcInfoList* Entries = new PVhcInfoList(); PVehicleInformation* InfoEntry; // Tmp implementation u16 LimitIndex = nStartIndex + nMaxCount; if ( !nMaxCount || ( VhcTypesNum < LimitIndex ) ) { LimitIndex = VhcTypesNum; } for ( u16 i = nStartIndex; ( i < LimitIndex ) ; ++i ) { InfoEntry = new PVehicleInformation(); if ( GetVehicleInfo( nCharId * 100 + VhcTypes[i], InfoEntry ) ) { Entries->push( InfoEntry ); } else { delete InfoEntry; } } return Entries; }
Vehicle::Vehicle(Unit *unit, VehicleEntry const *vehInfo) : me(unit), m_vehicleInfo(vehInfo), m_usableSeatNum(0), m_bonusHP(0) { for (uint32 i = 0; i < MAX_VEHICLE_SEATS; ++i) { if (uint32 seatId = m_vehicleInfo->m_seatID[i]) if (VehicleSeatEntry const *veSeat = sVehicleSeatStore.LookupEntry(seatId)) { m_Seats.insert(std::make_pair(i, VehicleSeat(veSeat))); if (veSeat->IsUsable()) ++m_usableSeatNum; } } // HACKY WAY, We must found a more generic way to handle this // Set inmunities since db ones are rewritten with player's ones switch (GetVehicleInfo()->m_ID) { case 160: me->SetControlled(true, UNIT_STAT_ROOT); me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true); me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK_DEST, true); case 158: me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_HEAL, true); me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_FEAR, true); me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_PERIODIC_HEAL, true); me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_STUN, true); me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_ROOT, true); me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_DECREASE_SPEED, true); me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_CONFUSE, true); me->ApplySpellImmune(0, IMMUNITY_ID, 49560, true); // Death Grip jump effect break; default: break; } }
/* ================ idBotAI::Vehicle_Ram_Attack_Movement ================ */ bool idBotAI::Vehicle_Ram_Attack_Movement() { proxyInfo_t enemyVehicleInfo; idBox enemyBox; if ( enemyInfo.enemyDist < 700.0f && botVehicleInfo->forwardSpeed < 100.0f && botVehicleInfo->type != HOG ) { //mal: somethings holding us up, we can't ram at this speed/dist! VEHICLE_COMBAT_MOVEMENT_STATE = NULL; return false; } if ( !Bot_VehicleCanRamClient( enemy ) ) { VEHICLE_COMBAT_MOVEMENT_STATE = NULL; return false; } if ( botWorld->clientInfo[ enemy ].proxyInfo.entNum != CLIENT_HAS_NO_VEHICLE ) { GetVehicleInfo( botWorld->clientInfo[ enemy ].proxyInfo.entNum, enemyVehicleInfo ); enemyBox = idBox( enemyVehicleInfo.bbox, enemyVehicleInfo.origin, enemyVehicleInfo.axis ); } else { enemyBox = idBox( botWorld->clientInfo[ enemy ].localBounds, botWorld->clientInfo[ enemy ].origin, botWorld->clientInfo[ enemy ].bodyAxis ); } if ( !InFrontOfVehicle( botVehicleInfo->entNum, enemyBox.GetCenter(), false ) ) { VEHICLE_COMBAT_MOVEMENT_STATE = NULL; return false; } Bot_MoveToGoal( enemyBox.GetCenter(), vec3_zero, SPRINT_ATTACK, NULLMOVETYPE ); //mal: Prepare for ramming speed! Ram them until they're dead, or we are.... Bot_LookAtLocation( enemyBox.GetCenter(), SMOOTH_TURN ); return true; }
/* ================== idBotAI::VehicleHasGunnerSeatOpen ================== */ bool idBotAI::VehicleHasGunnerSeatOpen( int entNum ) { bool hasSeat = true; int i; int j = 0; int numSeats = 1; proxyInfo_t vehicleInfo; botVehicleWeaponInfo_t weaponType = MINIGUN; GetVehicleInfo( entNum, vehicleInfo ); if ( !vehicleInfo.hasFreeSeat ) { //mal: that was fast.... return false; } if ( vehicleInfo.type == MCP ) { return true; } if ( vehicleInfo.type == BUFFALO ) { //mal: buffalo actually has 2 gunner seats, where most vehicles only have 1. numSeats = 3; } if ( vehicleInfo.type == TROJAN ) { weaponType = LAW; } for( i = 0; i < MAX_CLIENTS; i++ ) { if ( i == botNum && botVehicleInfo == NULL ) { continue; } if ( !ClientIsValid( i, -1 ) ) { continue; } const clientInfo_t &playerInfo = botWorld->clientInfo[ i ]; if ( playerInfo.team != botInfo->team ) { continue; } if ( playerInfo.proxyInfo.entNum != entNum ) { continue; } if ( playerInfo.proxyInfo.weapon != weaponType ) { continue; } j++; if ( j >= numSeats ) { hasSeat = false; break; } } return hasSeat; }
void Vehicle::ApplyAllImmunities() { // This couldn't be done in DB, because some spells have MECHANIC_NONE // Vehicles should be immune on Knockback ... _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true); _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK_DEST, true); // Mechanical units & vehicles ( which are not Bosses, they have own immunities in DB ) should be also immune on healing ( exceptions in switch below ) if (_me->ToCreature() && _me->ToCreature()->GetCreatureTemplate()->type == CREATURE_TYPE_MECHANICAL && !_me->ToCreature()->isWorldBoss()) { // Heal & dispel ... _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_HEAL, true); _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_HEAL_PCT, true); _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_DISPEL, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_PERIODIC_HEAL, true); // ... Shield & Immunity grant spells ... _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_SCHOOL_IMMUNITY, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_UNATTACKABLE, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_SCHOOL_ABSORB, true); _me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SHIELD, true); _me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_IMMUNE_SHIELD, true); // ... Resistance, Split damage, Change stats ... _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_DAMAGE_SHIELD, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_SPLIT_DAMAGE_PCT, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_RESISTANCE, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_STAT, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, true); } // Honour non movement flag (4) if (_me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE)) _me->SetControlled(true, UNIT_STATE_ROOT); // Different immunities for vehicles goes below switch (GetVehicleInfo()->m_ID) { // code below prevents a bug with movable cannons case 160: // Strand of the Ancients case 244: // Wintergrasp case 510: // Isle of Conquest case 452: // Isle of Conquest case 543: // Isle of Conquest _me->SetControlled(true, UNIT_STATE_ROOT); // why we need to apply this? we can simple add immunities to slow mechanic in DB _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_DECREASE_SPEED, true); break; case 321: // Pilgrims Bount: Chair _me->SetControlled(true, UNIT_STATE_ROOT); break; default: break; } }
Vehicle::Vehicle(Unit* unit, VehicleEntry const* vehInfo, uint32 creatureEntry) : UsableSeatNum(0), _me(unit), _vehicleInfo(vehInfo), _creatureEntry(creatureEntry), _status(STATUS_NONE) { for (uint32 i = 0; i < MAX_VEHICLE_SEATS; ++i) { if (uint32 seatId = _vehicleInfo->m_seatID[i]) if (VehicleSeatEntry const* veSeat = sVehicleSeatStore.LookupEntry(seatId)) { Seats.insert(std::make_pair(i, VehicleSeat(veSeat))); if (veSeat->CanEnterOrExit()) ++UsableSeatNum; } } // Vehicle Immunities switch (GetVehicleInfo()->m_ID) { case 160: case 116: _me->SetControlled(true, UNIT_STATE_ROOT); _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true); _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK_DEST, true); case 117: case 324: case 158: case 79: case 106: _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_HEAL_PCT, true); _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, true); _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_DISPEL, true); _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_HEAL, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_FEAR, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_PERIODIC_HEAL, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_STUN, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_ROOT, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_DECREASE_SPEED, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_CONFUSE, true); _me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_GRIP, true); _me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SHIELD, true); _me->ApplySpellImmune(0, IMMUNITY_ID, 13810, true); // Frost Trap _me->ApplySpellImmune(0, IMMUNITY_ID, 55741, true); // Desecration Rank 1 _me->ApplySpellImmune(0, IMMUNITY_ID, 68766, true); // Desecration Rank 2 break; default: break; } // Set or remove correct flags based on available seats. Will overwrite db data (if wrong). if (UsableSeatNum) _me->SetFlag(UNIT_NPC_FLAGS, (_me->GetTypeId() == TYPEID_PLAYER ? UNIT_NPC_FLAG_PLAYER_VEHICLE : UNIT_NPC_FLAG_SPELLCLICK)); else _me->RemoveFlag(UNIT_NPC_FLAGS, (_me->GetTypeId() == TYPEID_PLAYER ? UNIT_NPC_FLAG_PLAYER_VEHICLE : UNIT_NPC_FLAG_SPELLCLICK)); InitMovementInfoForBase(); }
void Vehicle::ApplyAllImmunities() { // This couldn't be done in DB, because Vehicle's immunities are overriden by Player's ones // Vehicles should be immune on Knockback, Deathgrip ... me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true); me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK_DEST, true); me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_GRIP, true); // ... Fear, Snare, Root, Stun ... me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_FEAR, true); me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SNARE, true); me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_ROOT, true); me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_STUN, true); me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_STUN, true); me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DISORIENTED, true); me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_CONFUSE, true); // Mechanical units & vehicles ( which are not Bosses, they have own immunities in DB ) should be also immune on healing ( exceptions in switch below ) if (me->ToCreature() && me->ToCreature()->GetCreatureInfo()->type == CREATURE_TYPE_MECHANICAL && !me->ToCreature()->isWorldBoss()) { // Heal & dispel ... me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_HEAL, true); me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_PERIODIC_HEAL, true); // ... Shield & Immunity grant spells ... me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_SCHOOL_IMMUNITY, true); me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_UNATTACKABLE, true); me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_SCHOOL_ABSORB, true); me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SHIELD, true); me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_IMMUNE_SHIELD , true); // ... Resistance, Split damage, Speed Increase, ... me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_DAMAGE_SHIELD, true); me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_SPLIT_DAMAGE_PCT, true); me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_RESISTANCE, true); me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_STAT, true); me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, true); me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_INCREASE_SPEED, true); } // Different immunities for vehicles goes below switch (GetVehicleInfo()->m_ID) { case 160: me->SetControlled(true, UNIT_STAT_ROOT); me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_DECREASE_SPEED, true); break; default: break; } }
Vehicle::Vehicle(Unit* unit, VehicleEntry const* vehInfo, uint32 creatureEntry) : _me(unit), _vehicleInfo(vehInfo), _usableSeatNum(0), _creatureEntry(creatureEntry) { for (uint32 i = 0; i < MAX_VEHICLE_SEATS; ++i) { if (uint32 seatId = _vehicleInfo->m_seatID[i]) if (VehicleSeatEntry const* veSeat = sVehicleSeatStore.LookupEntry(seatId)) { Seats.insert(std::make_pair(i, VehicleSeat(veSeat))); if (veSeat->CanEnterOrExit()) ++_usableSeatNum; } } // HACKY WAY, We must found a more generic way to handle this // Set inmunities since db ones are rewritten with player's ones switch (GetVehicleInfo()->m_ID) { case 160: case 116: case 452: case 453: case 510: _me->SetControlled(true, UNIT_STATE_ROOT); _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true); _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK_DEST, true); case 117: case 324: case 158: case 79: case 106: _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_HEAL_PCT, true); _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, true); _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_DISPEL, true); _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_HEAL, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_FEAR, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_PERIODIC_HEAL, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_STUN, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_ROOT, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_DECREASE_SPEED, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_CONFUSE, true); _me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_GRIP, true); _me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SHIELD, true); _me->ApplySpellImmune(0, IMMUNITY_ID, 13810, true); // Frost Trap _me->ApplySpellImmune(0, IMMUNITY_ID, 55741, true); // Desecration Rank 1 _me->ApplySpellImmune(0, IMMUNITY_ID, 68766, true); // Desecration Rank 2 break; default: break; } InitMovementInfoForBase(); }
void Vehicle::InitMovementInfoForBase() { uint32 vehicleFlags = GetVehicleInfo()->m_flags; if (vehicleFlags & VEHICLE_FLAG_NO_STRAFE) _me->AddExtraUnitMovementFlag(MOVEMENTFLAG2_NO_STRAFE); if (vehicleFlags & VEHICLE_FLAG_NO_JUMPING) _me->AddExtraUnitMovementFlag(MOVEMENTFLAG2_NO_JUMPING); if (vehicleFlags & VEHICLE_FLAG_FULLSPEEDTURNING) _me->AddExtraUnitMovementFlag(MOVEMENTFLAG2_FULL_SPEED_TURNING); if (vehicleFlags & VEHICLE_FLAG_ALLOW_PITCHING) _me->AddExtraUnitMovementFlag(MOVEMENTFLAG2_ALWAYS_ALLOW_PITCHING); if (vehicleFlags & VEHICLE_FLAG_FULLSPEEDPITCHING) _me->AddExtraUnitMovementFlag(MOVEMENTFLAG2_FULL_SPEED_PITCHING); }
/* ================ idBotAI::Enter_Vehicle_Air_Movement ================ */ bool idBotAI::Enter_Vehicle_Air_Movement() { proxyInfo_t enemyVehicleInfo; combatMoveType = VEHICLE_AIR_MOVEMENT; combatMoveActionGoal = ACTION_NULL; combatMoveTooCloseRange = 0.0f; if ( botWorld->clientInfo[ enemy ].proxyInfo.entNum != CLIENT_HAS_NO_VEHICLE ) { GetVehicleInfo( botWorld->clientInfo[ enemy ].proxyInfo.entNum, enemyVehicleInfo ); if ( enemyVehicleInfo.isAirborneVehicle ) { if ( botVehicleInfo->type == BUFFALO ) { VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Buffalo_Air_To_Air_Movement; lastMoveNode = "Buffalo Air To Air Combat"; combatMoveTime = botWorld->gameLocalInfo.time + 500; } else { VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Vehicle_Air_To_Air_Movement; lastMoveNode = "Vehicle Air To Air Combat"; } } else { if ( botVehicleInfo->type == BUFFALO ) { VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Buffalo_Air_To_Ground_Movement; lastMoveNode = "Buffalo Air To Ground Combat"; combatMoveTime = botWorld->gameLocalInfo.time + 500; } else { combatKeepMovingTime = 0; VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Vehicle_Air_To_Ground_Movement; lastMoveNode = "Vehicle Air To Ground Combat"; } } } else { if ( botVehicleInfo->type == BUFFALO ) { VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Buffalo_Air_To_Ground_Movement; lastMoveNode = "Buffalo Air To Ground Combat"; combatMoveTime = botWorld->gameLocalInfo.time + 500; } else { combatKeepMovingTime = 0; VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Vehicle_Air_To_Ground_Movement; lastMoveNode = "Vehicle Air To Ground Combat"; } } rocketTime = 0; return true; }
void Vehicle::ApplyAllImmunities() { // This couldn't be done in DB, because some spells have MECHANIC_NONE // Vehicles should be immune on Knockback ... _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true); _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK_DEST, true); // Mechanical units & vehicles ( which are not Bosses, they have own immunities in DB ) should be also immune on healing ( exceptions in switch below ) if (_me->ToCreature() && _me->ToCreature()->GetCreatureInfo()->type == CREATURE_TYPE_MECHANICAL && !_me->ToCreature()->isWorldBoss()) { // Heal & dispel ... _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_HEAL, true); _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_HEAL_PCT, true); _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_DISPEL, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_PERIODIC_HEAL, true); // ... Shield & Immunity grant spells ... _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_SCHOOL_IMMUNITY, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_UNATTACKABLE, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_SCHOOL_ABSORB, true); _me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SHIELD, true); _me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_IMMUNE_SHIELD , true); // ... Resistance, Split damage, Change stats ... _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_DAMAGE_SHIELD, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_SPLIT_DAMAGE_PCT, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_RESISTANCE, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_STAT, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, true); } // Different immunities for vehicles goes below switch (GetVehicleInfo()->m_ID) { case 160: _me->SetControlled(true, UNIT_STAT_ROOT); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_DECREASE_SPEED, true); break; default: break; } }
uint16 Vehicle::GetExtraMovementFlagsForBase() const { uint16 movementMask = MOVEMENTFLAG2_NONE; uint32 vehicleFlags = GetVehicleInfo()->m_flags; if (vehicleFlags & VEHICLE_FLAG_NO_STRAFE) movementMask |= MOVEMENTFLAG2_NO_STRAFE; if (vehicleFlags & VEHICLE_FLAG_NO_JUMPING) movementMask |= MOVEMENTFLAG2_NO_JUMPING; if (vehicleFlags & VEHICLE_FLAG_FULLSPEEDTURNING) movementMask |= MOVEMENTFLAG2_FULL_SPEED_TURNING; if (vehicleFlags & VEHICLE_FLAG_ALLOW_PITCHING) movementMask |= MOVEMENTFLAG2_ALWAYS_ALLOW_PITCHING; if (vehicleFlags & VEHICLE_FLAG_FULLSPEEDPITCHING) movementMask |= MOVEMENTFLAG2_FULL_SPEED_PITCHING; sLog->outDebug("Vehicle::GetExtraMovementFlagsForBase() returned %u", movementMask); return movementMask; }
/* ================ idBotAI::Bot_FindBestVehicleCombatMovement Finds the best combat movement for the bot while in a vehicle. ================ */ bool idBotAI::Bot_FindBestVehicleCombatMovement() { bool vehicleCanRamClient; //mal: sounds a bit... dirty, doesn't it? bool vehicleGunnerSeatOpen; bool hasAttackedCriticalMate = false; bool enemyReachable = false; bool enemyHasVehicle = false; proxyInfo_t enemyVehicleInfo; const clientInfo_t& enemyPlayerInfo = botWorld->clientInfo[ enemy ]; if ( enemyPlayerInfo.proxyInfo.entNum != CLIENT_HAS_NO_VEHICLE ) { GetVehicleInfo( enemyPlayerInfo.proxyInfo.entNum, enemyVehicleInfo ); enemyHasVehicle = true; } combatMoveFailedCount = 0; combatMoveTime = -1; if ( botInfo->proxyInfo.weapon == NULL_VEHICLE_WEAPON && botVehicleInfo->driverEntNum != botNum ) { return false; } //mal: this shouldn't really ever happen, but may if the bot is moving between positions in a vehicle. Or if a human entered/exited a vehicle at just the right/wrong time. if ( ( botInfo->proxyInfo.weapon == MINIGUN || botInfo->proxyInfo.weapon == LAW || botInfo->proxyInfo.weapon == PERSONAL_WEAPON ) && botVehicleInfo->driverEntNum != botNum ) { VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_NULL_Movement; //mal: just sit there, and shoot the enemy. return true; } if ( botVehicleInfo->type > ICARUS ) { VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_Air_Movement; return true; } //mal: this more often then not causes issues /* if ( enemyHasVehicle ) { if ( enemyVehicleInfo.type == HOG && enemyInfo.enemyDist < 3000.0f && botVehicleInfo->driverEntNum == botNum ) { //mal: never stand around if a hog has us in his sights. VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_Random_Movement; return true; } } */ vehicleGunnerSeatOpen = VehicleHasGunnerSeatOpen( botInfo->proxyInfo.entNum ); if ( enemyPlayerInfo.lastAttackClient > - 1 && enemyPlayerInfo.lastAttackClient < MAX_CLIENTS ) { if ( botWorld->clientInfo[ enemyPlayerInfo.lastAttackClient ].team == botInfo->team && enemyPlayerInfo.lastAttackClientTime + 3000 > botWorld->gameLocalInfo.time ) { if ( Client_IsCriticalForCurrentObj( enemyPlayerInfo.lastAttackClient, 2000.0f ) || ClientHasObj( enemyPlayerInfo.lastAttackClient ) ) { hasAttackedCriticalMate = true; } } } Bot_SetupVehicleMove( vec3_zero, enemy, ACTION_NULL ); if ( botAAS.hasPath && botAAS.path.travelTime < Bot_ApproxTravelTimeToLocation( botInfo->origin, enemyPlayerInfo.origin, true ) * TRAVEL_TIME_MULTIPLY ) { enemyReachable = true; } if ( botInfo->proxyInfo.weapon == NULL_VEHICLE_WEAPON && botVehicleInfo->driverEntNum == botNum ) { vehicleCanRamClient = Bot_VehicleCanRamClient( enemy ); if ( botVehicleInfo->type == HOG ) { if ( vehicleCanRamClient && InFrontOfVehicle( botVehicleInfo->entNum, enemyPlayerInfo.origin, true ) ) { VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_Ram_Attack_Movement; //mal: ram them! Thats our only weapon. return true; } if ( enemyReachable && enemyHasVehicle ) { if ( enemyVehicleInfo.type != HUSKY ) { VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_Chase_Movement; //mal: move in for a closer kill, THEN ram them. return true; } } } if ( botVehicleInfo->type == BADGER && enemyInfo.enemyDist < 1500.0f && vehicleCanRamClient && enemyPlayerInfo.proxyInfo.entNum == CLIENT_HAS_NO_VEHICLE && botVehicleInfo->driverEntNum == botNum ) { VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_Ram_Attack_Movement; //mal: 10 points! Fun for the whole family. return true; } if ( !vehicleGunnerSeatOpen ) { if ( enemyInfo.enemyDist < 2500.0f ) { VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_Stand_Ground_Movement; //mal: just sit there, let our gunner get a chance to kill the enemy. } else { if ( enemyReachable || enemyInfo.enemyDist > 1500.0f ) { VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_Chase_Movement; //mal: move in for a closer kill. } else { VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_Stand_Ground_Movement; //mal: just sit there, let our gunner get a chance to kill the enemy. } } return true; } else { if ( enemyPlayerInfo.proxyInfo.entNum == CLIENT_HAS_NO_VEHICLE ) { if ( enemyInfo.enemyDist < 6000.0f && ( vehicleCanRamClient || hasAttackedCriticalMate ) ) { //mal: if an important mate is under attack, we'll fight to the end, even if its just to draw the enemies fire. VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_Ram_Attack_Movement; //mal: ram them! Thats our only weapon. return true; } } else { Bot_IgnoreEnemy( enemy, 15000 ); return false; } //mal: if all else fails, we have no choice but to ignore this enemy. } } if ( ( botInfo->proxyInfo.weapon == MINIGUN || botInfo->proxyInfo.weapon == LAW || botInfo->proxyInfo.weapon == PERSONAL_WEAPON ) && botVehicleInfo->driverEntNum != botNum ) { VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_NULL_Movement; //mal: just sit there, and shoot the enemy. return true; } if ( ( botInfo->proxyInfo.weapon == MINIGUN || botInfo->proxyInfo.weapon == LAW || botInfo->proxyInfo.weapon == PERSONAL_WEAPON ) && botVehicleInfo->driverEntNum == botNum ) { if ( botThreadData.random.RandomInt( 100 ) > 50 && enemyInfo.enemyDist < 1500.0f ) { VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_Stand_Ground_Movement; } else { VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_Chase_Movement; //mal: move around a bit to make ourselves harder to hit. } return true; } if ( botVehicleInfo->type == GOLIATH && botVehicleInfo->driverEntNum == botNum ) { VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_Stand_Ground_Movement; return true; } if ( botInfo->proxyInfo.weapon == TANK_GUN && botVehicleInfo->driverEntNum == botNum ) { if ( !enemyReachable && enemyInfo.enemyDist < 3000.0f ) { //mal: dont do chase movement of our enemy, if we cant reach him. VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_Stand_Ground_Movement; } else { if ( enemyAcquireTime + 10000 < botWorld->gameLocalInfo.time && botInfo->lastAttackClientTime + 10000 < botWorld->gameLocalInfo.time ) { proxyInfo_t enemyVehicleInfo; GetVehicleInfo( enemyPlayerInfo.proxyInfo.entNum, enemyVehicleInfo ); if ( enemyVehicleInfo.entNum != 0 && enemyVehicleInfo.type >= ICARUS ) { //mal: dont chase air vehicles around - this looks retarded. VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_Stand_Ground_Movement; } else { VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_Chase_Movement; //mal: haven't had much success hitting our enemy - so chase him for a better shot. } } else { // if ( botThreadData.random.RandomInt( 100 ) > 40 ) { VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_Stand_Ground_Movement; // } else { // VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_Chase_Movement; //mal: move around a bit to make ourselves harder to hit. // } } } return true; } //mal_TODO: add support for air vehicles too...... botThreadData.Warning( "Can't find a move that suits bot %i and his vehicle!", botNum ); return false; }
bool Vehicle::AddPassenger(Unit *unit, int8 seatId) { if (unit->GetVehicle() != this) return false; // don't allow vehicles in arena if (unit->GetTypeId() == TYPEID_PLAYER && unit->GetMap()->IsBattleArena()) return false; SeatMap::iterator seat; if (seatId < 0) // no specific seat requirement { for (seat = m_Seats.begin(); seat != m_Seats.end(); ++seat) if (!seat->second.passenger && seat->second.seatInfo->IsUsable()) break; if (seat == m_Seats.end()) // no available seat return false; } else { seat = m_Seats.find(seatId); if (seat == m_Seats.end()) return false; if (seat->second.passenger) seat->second.passenger->ExitVehicle(); ASSERT(!seat->second.passenger); } sLog.outDebug("Unit %s enter vehicle entry %u id %u dbguid %u seat %d", unit->GetName(), me->GetEntry(), m_vehicleInfo->m_ID, me->GetGUIDLow(), (int32)seat->first); seat->second.passenger = unit; if (seat->second.seatInfo->IsUsable()) { ASSERT(m_usableSeatNum); --m_usableSeatNum; if (!m_usableSeatNum) { if (me->GetTypeId() == TYPEID_PLAYER) me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_PLAYER_VEHICLE); else me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); } } if (seat->second.seatInfo->m_flags && !(seat->second.seatInfo->m_flags & VEHICLE_SEAT_FLAG_UNK11)) { switch (GetVehicleInfo()->m_ID) { case 342: //Ignis case 335: //XT-002 case 380: //Kologarn's Right Arm break; default: unit->addUnitState(UNIT_STAT_ONVEHICLE); break; } } unit->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); VehicleSeatEntry const *veSeat = seat->second.seatInfo; unit->m_movementInfo.t_pos.m_positionX = veSeat->m_attachmentOffsetX; unit->m_movementInfo.t_pos.m_positionY = veSeat->m_attachmentOffsetY; unit->m_movementInfo.t_pos.m_positionZ = veSeat->m_attachmentOffsetZ; unit->m_movementInfo.t_pos.m_orientation = 0; unit->m_movementInfo.t_time = 0; // 1 for player unit->m_movementInfo.t_seat = seat->first; if (me->GetTypeId() == TYPEID_UNIT && unit->GetTypeId() == TYPEID_PLAYER && seat->first == 0 && seat->second.seatInfo->m_flags & VEHICLE_SEAT_FLAG_CAN_CONTROL) { if (!me->SetCharmedBy(unit, CHARM_TYPE_VEHICLE)) ASSERT(false); if (VehicleScalingInfo const *scalingInfo = sObjectMgr.GetVehicleScalingInfo(m_vehicleInfo->m_ID)) { Player *plr = unit->ToPlayer(); float averageItemLevel = plr->GetAverageItemLevel(); if (averageItemLevel < scalingInfo->baseItemLevel) averageItemLevel = scalingInfo->baseItemLevel; averageItemLevel -= scalingInfo->baseItemLevel; m_bonusHP = uint32(me->GetMaxHealth() * (averageItemLevel * scalingInfo->scalingFactor)); me->SetMaxHealth(me->GetMaxHealth() + m_bonusHP); me->SetHealth(me->GetHealth() + m_bonusHP); } } if (me->IsInWorld()) { unit->SendMonsterMoveTransport(me); if (me->GetTypeId() == TYPEID_UNIT) { if (me->ToCreature()->IsAIEnabled) me->ToCreature()->AI()->PassengerBoarded(unit, seat->first, true); // update all passenger's positions RelocatePassengers(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation()); } } if (GetBase()->GetTypeId() == TYPEID_UNIT) sScriptMgr.OnAddPassenger(this, unit, seatId); return true; }
/* ================== idBotAI::Bot_PickBestVehicleWeapon See what the best weapon is that we have at our disposal - we'll change our position in this vehicle if need be to get access to a ( better ) weapon. ================== */ void idBotAI::Bot_PickBestVehicleWeapon() { bool enemyInAirborneVehicle = false; bool enemyInGroundVehicle = false; bool needMovementUpdate = false; bool enemyOnFoot = false; bool hasGunnerSeatOpen; bool enemyReachable = false; if ( weapSwitchTime > botWorld->gameLocalInfo.time ) { return; } if ( botVehicleInfo->type == ICARUS ) { return; } proxyInfo_t enemyVehicleInfo; idVec3 vec = botWorld->clientInfo[ enemy ].origin - botInfo->origin; float dist = vec.LengthSqr(); hasGunnerSeatOpen = VehicleHasGunnerSeatOpen( botInfo->proxyInfo.entNum ); if ( botWorld->clientInfo[ enemy ].proxyInfo.entNum != CLIENT_HAS_NO_VEHICLE ) { GetVehicleInfo( botWorld->clientInfo[ enemy ].proxyInfo.entNum, enemyVehicleInfo ); if ( enemyVehicleInfo.isAirborneVehicle ) { enemyInAirborneVehicle = true; } else { enemyInGroundVehicle = true; } } else { enemyOnFoot = true; } Bot_SetupVehicleMove( vec3_zero, enemy, ACTION_NULL ); if ( botAAS.hasPath && botAAS.path.travelTime < Bot_ApproxTravelTimeToLocation( botInfo->origin, botWorld->clientInfo[ enemy ].origin, true ) * TRAVEL_TIME_MULTIPLY ) { enemyReachable = true; } switch( botVehicleInfo->type ) { case TITAN: if ( botVehicleInfo->driverEntNum == botNum ) { if ( enemyInAirborneVehicle && enemyInfo.enemyDist <= TANK_MINIGUN_RANGE && hasGunnerSeatOpen ) { botUcmd->botCmds.becomeGunner = true; needMovementUpdate = true; break; } } else { if ( ( enemyInAirborneVehicle && enemyInfo.enemyDist > TANK_MINIGUN_RANGE && botVehicleInfo->driverEntNum == -1 ) || !enemyInAirborneVehicle ) { botUcmd->botCmds.becomeDriver = true; needMovementUpdate = true; break; } } break; case TROJAN: if ( botInfo->proxyInfo.weapon == LAW ) { if ( botVehicleInfo->driverEntNum == -1 ) { if ( ( !enemyInAirborneVehicle && !enemyInGroundVehicle ) || enemyInfo.enemyDist < 700.0f || enemyInfo.enemyDist > WEAPON_LOCK_DIST ) { botUcmd->botCmds.becomeDriver = true; //mal: using the LAW to lock onto our vehicle enemy makes sense ( the drivers MG is a joke in this case ). needMovementUpdate = true; break; } } } if ( botVehicleInfo->driverEntNum == botNum ) { if ( ( enemyInAirborneVehicle || enemyInGroundVehicle ) && hasGunnerSeatOpen && dist < Square( WEAPON_LOCK_DIST ) ) { botUcmd->botCmds.becomeGunner = true; //mal: using the LAW to lock onto our airborne enemy makes sense ( the drivers MG is a joke in this case ). needMovementUpdate = true; break; } } if ( botInfo->proxyInfo.weapon == NULL_VEHICLE_WEAPON ) { if ( botVehicleInfo->driverEntNum == -1 ) { botUcmd->botCmds.becomeDriver = true; needMovementUpdate = true; } else if ( VehicleHasGunnerSeatOpen( botVehicleInfo->entNum ) ) { botUcmd->botCmds.becomeGunner = true; needMovementUpdate = true; } break; }//mal: if we're the driver, stay as the driver! break; case BADGER: if ( botVehicleInfo->driverEntNum == botNum ) { //mal: we're the driver, if the turret is available, we may jump into it to fight enemies. if ( hasGunnerSeatOpen && vehicleDriverTime < botWorld->gameLocalInfo.time && enemyReachable && enemyInfo.enemyDist > 700.0f && enemyVehicleInfo.type != HOG ) { if ( botThreadData.random.RandomInt( 100 ) > 50 ) { vehicleDriverTime = botWorld->gameLocalInfo.time + 15000; break; } if ( ( enemyInAirborneVehicle || ( enemyInfo.enemyDist < 3000.0f && enemyInfo.enemyDist > 700.0f ) ) && vehicleGunnerTime + 30000 < botWorld->gameLocalInfo.time && enemyInfo.enemyVisible ) { //mal: dont do this if enemy too far away, or its been too soon since we last did this. botUcmd->botCmds.becomeGunner = true; vehicleGunnerTime = botWorld->gameLocalInfo.time + 15000; needMovementUpdate = true; break; } } } if ( botInfo->proxyInfo.weapon == PERSONAL_WEAPON ) { if ( hasGunnerSeatOpen && botVehicleInfo->driverEntNum != -1 ) { botUcmd->botCmds.becomeGunner = true; needMovementUpdate = true; break; } //mal: our gunner may have been killed, or maybe he jumped out some time ago - take his place. if ( botVehicleInfo->driverEntNum == -1 ) { botUcmd->botCmds.becomeDriver = true; needMovementUpdate = true; break; } } if ( botInfo->proxyInfo.weapon == MINIGUN ) { if ( botVehicleInfo->driverEntNum == -1 ) { if ( vehicleGunnerTime < botWorld->gameLocalInfo.time || !enemyInfo.enemyVisible ) { //mal: even if we had a driver and he bailed, become the driver for a better shot, then can go back to the gun. botUcmd->botCmds.becomeDriver = true; needMovementUpdate = true; break; } } } if ( botInfo->proxyInfo.weapon == NULL_VEHICLE_WEAPON && botVehicleInfo->driverEntNum != botNum ) { if ( botVehicleInfo->driverEntNum == -1 ) { botUcmd->botCmds.becomeDriver = true; needMovementUpdate = true; } else if ( VehicleHasGunnerSeatOpen( botVehicleInfo->entNum ) ) { botUcmd->botCmds.becomeGunner = true; needMovementUpdate = true; } else if ( botVehicleInfo->hasFreeSeat ) { needMovementUpdate = true; botUcmd->botCmds.activate = true; //mal: rotate to one of the back seats. } }//mal: if we're the driver, stay as the driver! break; case PLATYPUS: if ( botVehicleInfo->driverEntNum == botNum ) { //mal: we're the driver, if the turret is available, we may jump into it to fight enemies. if ( hasGunnerSeatOpen ) { if ( enemyInfo.enemyDist < 1500.0f && vehicleGunnerTime + 30000 < botWorld->gameLocalInfo.time && enemyInfo.enemyVisible ) { //mal: dont do this if enemy too far away, or its been too soon since we last did this. botUcmd->botCmds.becomeGunner = true; vehicleGunnerTime = botWorld->gameLocalInfo.time + 10000; needMovementUpdate = true; } } //mal: if we have a gunner, we'll try to get a better shot for him, so that he can cut down our enemies. } if ( botInfo->proxyInfo.weapon == MINIGUN ) { if ( botVehicleInfo->driverEntNum == -1 ) { if ( vehicleGunnerTime < botWorld->gameLocalInfo.time || !enemyInfo.enemyVisible ) { //mal: even if we had a driver and he bailed, become the driver for a better shot, then can go back to the gun. botUcmd->botCmds.becomeDriver = true; needMovementUpdate = true; } } } break; case DESECRATOR: if ( botVehicleInfo->driverEntNum == botNum ) { if ( enemyInAirborneVehicle && enemyInfo.enemyDist <= TANK_MINIGUN_RANGE && hasGunnerSeatOpen ) { botUcmd->botCmds.becomeGunner = true; needMovementUpdate = true; break; } } else { if ( ( enemyInAirborneVehicle && enemyInfo.enemyDist > TANK_MINIGUN_RANGE && botVehicleInfo->driverEntNum == -1 ) || !enemyInAirborneVehicle ) { botUcmd->botCmds.becomeDriver = true; needMovementUpdate = true; break; } } break; case HOG: if ( botInfo->proxyInfo.weapon == MINIGUN ) { if ( botVehicleInfo->driverEntNum == -1 ) { if ( vehicleGunnerTime < botWorld->gameLocalInfo.time || !enemyInfo.enemyVisible || botWorld->clientInfo[ enemy ].proxyInfo.entNum != CLIENT_HAS_NO_VEHICLE && !enemyInAirborneVehicle ) { //mal: even if we had a driver and he bailed, become the driver for a better shot, then can go back to the gun. botUcmd->botCmds.becomeDriver = true; needMovementUpdate = true; } //mal: we'll prefer to ram our enemies who are in vehicles } } if ( botVehicleInfo->driverEntNum == botNum && ( !Bot_VehicleCanRamClient( enemy ) || VEHICLE_COMBAT_MOVEMENT_STATE == NULL || combatMoveType != VEHICLE_RAM_ATTACK_MOVEMENT ) ) { if ( ( enemyInAirborneVehicle || ( enemyInfo.enemyDist < 3000.0f && enemyInfo.enemyDist > 700.0f ) ) && vehicleGunnerTime + 30000 < botWorld->gameLocalInfo.time && enemyInfo.enemyVisible ) { botUcmd->botCmds.becomeGunner = true; vehicleGunnerTime = botWorld->gameLocalInfo.time + 10000; needMovementUpdate = true; } } break; case ANANSI: case HORNET: if ( botInfo->proxyInfo.weapon == MINIGUN ) { if ( botVehicleInfo->driverEntNum == -1 ) { botUcmd->botCmds.becomeDriver = true; //mal: our coward of a pilot bailed on us... take the controls! needMovementUpdate = true; } } if ( botVehicleInfo->driverEntNum == botNum ) { if ( botInfo->proxyInfo.weapon == LAW ) { //mal: law is better against other vehicles if ( botWorld->clientInfo[ enemy ].proxyInfo.entNum == CLIENT_HAS_NO_VEHICLE ) { botUcmd->botCmds.switchVehicleWeap = true; } else { if ( botInfo->proxyInfo.weaponIsReady == false && rocketTime < botWorld->gameLocalInfo.time && botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY ) { //mal: use rockets if LAW outta charge rocketTime = botWorld->gameLocalInfo.time + 2000; botUcmd->botCmds.switchVehicleWeap = true; } } } if ( botInfo->proxyInfo.weapon == ROCKETS ) { //mal: rockets are nice against slow moving ground targets. if ( botWorld->clientInfo[ enemy ].proxyInfo.entNum != CLIENT_HAS_NO_VEHICLE && rocketTime < botWorld->gameLocalInfo.time ) { botUcmd->botCmds.switchVehicleWeap = true; } } } break; } if ( needMovementUpdate ) { COMBAT_MOVEMENT_STATE = NULL; VEHICLE_COMBAT_MOVEMENT_STATE = NULL; vehicleUpdateTime = botWorld->gameLocalInfo.time + 500; } weapSwitchTime = botWorld->gameLocalInfo.time + 1500; }
/* ================== idBotAI::Bot_VehicleCanRamClient See if the vehicle can ram the client in question, in the vehicle the bot is in. ================== */ bool idBotAI::Bot_VehicleCanRamClient( int clientNum ) { int areaNum; proxyInfo_t enemyVehicleInfo; idVec3 vec; idVec3 enemyOrg; if ( botVehicleInfo->type != HOG && botVehicleInfo->health < ( botVehicleInfo->maxHealth / 4 ) && botWorld->clientInfo[ clientNum ].proxyInfo.entNum != CLIENT_HAS_NO_VEHICLE ) { return false; } //mal: most vehicles can't handle ramming other vehicles while damaged - clients on foot are ALWAYS ok tho! >:-D if ( botVehicleInfo->flags & WATER || botVehicleInfo->inWater || botVehicleInfo->type == GOLIATH || botVehicleInfo->type == DESECRATOR || botVehicleInfo->flags & PERSONAL || botVehicleInfo->flags & AIR ) { return false; } if ( botVehicleInfo->type != HOG && botVehicleInfo->forwardSpeed < 100.0f && enemyInfo.enemyDist < 700.0f ) { return false; } if ( botWorld->clientInfo[ clientNum ].proxyInfo.entNum == CLIENT_HAS_NO_VEHICLE ) { enemyOrg = botWorld->clientInfo[ clientNum ].origin; areaNum = botWorld->clientInfo[ clientNum ].areaNumVehicle; if ( botWorld->clientInfo[ clientNum ].inWater || !botWorld->clientInfo[ enemy ].inPlayZone ) { return false; } if ( !botWorld->clientInfo[ clientNum ].hasGroundContact ) { return false; } } else { GetVehicleInfo( botWorld->clientInfo[ clientNum ].proxyInfo.entNum, enemyVehicleInfo ); enemyOrg = enemyVehicleInfo.origin; areaNum = enemyVehicleInfo.areaNumVehicle; if ( enemyVehicleInfo.isAirborneVehicle ) { return false; } if ( enemyVehicleInfo.isEmpty ) { return false; } if ( !enemyVehicleInfo.inPlayZone ) { return false; } if ( enemyVehicleInfo.inWater ) { return false; } } bool canReach = botThreadData.Nav_IsDirectPath( AAS_VEHICLE, botInfo->team, botInfo->areaNumVehicle, botVehicleInfo->origin, enemyOrg ); if ( !canReach ) { return false; } return true; }
/* ================ idBotAI::Bot_ShouldVehicleChaseHiddenEnemy ================ */ bool idBotAI::Bot_ShouldVehicleChaseHiddenEnemy() { proxyInfo_t enemyVehicleInfo; idVec3 vec; chasingEnemy = false; if ( ClientHasObj( botNum ) || Client_IsCriticalForCurrentObj( botNum, -1.0f ) ) { //mal: never chase if we are important! return false; } if ( botVehicleInfo->driverEntNum != botNum ) { //mal: we dont get the choice to chase someone if we're not the driver! return false; } if ( botVehicleInfo->health <= ( botVehicleInfo->maxHealth / 4 ) && !ClientHasObj( enemy ) ) { //mal: if we're in pretty bad shape, randomly decide to sometimes give up the fight.... if ( botThreadData.random.RandomInt( 100 ) > 50 ) { return false; } } if ( ( botVehicleInfo->flags & PERSONAL ) || botInfo->proxyInfo.weapon == NULL_VEHICLE_WEAPON && !ClientHasObj( enemy ) ) { return false; } //mal: if we dont have a vehicle weapon to fight with, or we're in a personal transport, dont go chasing ppl. if ( botWorld->clientInfo[ enemy ].proxyInfo.entNum != CLIENT_HAS_NO_VEHICLE ) { GetVehicleInfo( botWorld->clientInfo[ enemy ].proxyInfo.entNum, enemyVehicleInfo ); if ( enemyVehicleInfo.inWater && !botVehicleInfo->isAirborneVehicle || !( botVehicleInfo->flags & WATER ) ) { return false; } //mal: hes in the water, but we can't chase him, so forget him! if ( !ClientHasObj( enemy ) && !Client_IsCriticalForCurrentObj( enemy, 2000.0f ) ) { if ( botThreadData.random.RandomInt( 100 ) > 50 ) { return false; } } } if ( AIStack.STACK_AI_NODE != NULL && AIStack.isPriority != false && !ClientHasObj( enemy ) ) { return false; } // we have something important on our mind, and cant chase ATM - UNLESS they have the obj! Always chase them! vec = enemyInfo.enemy_LS_Pos - botInfo->origin; if ( vec.LengthSqr() > Square( ENEMY_CHASE_DIST ) ) { return false; } // too far away to chase vec = enemyInfo.enemy_LS_Pos - botWorld->clientInfo[ enemy ].origin; if ( vec.LengthSqr() > Square( 900.0f ) && !ClientHasObj( enemy ) && !Client_IsCriticalForCurrentObj( enemy, 1500.0f ) ) { // unless he's REALLY close or a threat, sometimes we'll stop the chase, just because.... if ( botThreadData.random.RandomInt( 100 ) > 50 ) { return false; } } chasingEnemy = true; if ( ClientHasObj( enemy ) ) { chaseEnemyTime = botWorld->gameLocalInfo.time + 30000; } else if ( Client_IsCriticalForCurrentObj( enemy, 1500.0f ) ) { chaseEnemyTime = botWorld->gameLocalInfo.time + 15000; } else { chaseEnemyTime = botWorld->gameLocalInfo.time + 7000; } return true; }
/* ================ idBotAI::Bot_VehicleFindBetterEnemy ================ */ bool idBotAI::Bot_VehicleFindBetterEnemy() { int i; int entClientNum = enemy; float dist; float entDist; proxyInfo_t vehicleInfo; proxyInfo_t enemyVehicleInfo; idVec3 vec; if ( enemy == -1 ) { //mal: we lost our enemy for some reason, so just skip finding a new one til next frame. return false; } if ( ignoreNewEnemiesWhileInVehicleTime > botWorld->gameLocalInfo.time ) { return false; } if ( botWorld->clientInfo[ enemy ].proxyInfo.entNum != CLIENT_HAS_NO_VEHICLE ) { //mal: if we're attacking the MCP, its the priority. if ( botWorld->clientInfo[ enemy ].proxyInfo.entNum == botWorld->botGoalInfo.botGoal_MCP_VehicleNum ) { return false; } } GetVehicleInfo( botWorld->clientInfo[ enemy ].proxyInfo.entNum, enemyVehicleInfo ); if ( enemyVehicleInfo.entNum > 0 && ( enemyVehicleInfo.type == ANANSI || enemyVehicleInfo.type == HORNET ) ) { //mal: stay in dogfights! return false; } const clientInfo_t& enemyPlayerInfo = botWorld->clientInfo[ enemy ]; vec = enemyPlayerInfo.origin - botInfo->origin; entDist = vec.LengthSqr(); if ( !enemyInfo.enemyVisible ) { //mal: if we can't see our current enemy, more likely to attack a visible enemy. entDist = idMath::INFINITY; } if ( botWorld->gameLocalInfo.botSkill == BOT_SKILL_DEMO && !botWorld->botGoalInfo.gameIsOnFinalObjective && ( !enemyPlayerInfo.isBot || enemyPlayerInfo.isActor ) ) { //mal: dont worry about keeping our human target in training mode, unless its the final obj... entDist += Square( TRAINING_MODE_RANGE_ADDITION ); } bool curEnemyNotInVehicle = false; if ( botWorld->clientInfo[ enemy ].proxyInfo.entNum == CLIENT_HAS_NO_VEHICLE && !ClientIsDefusingOurTeamCharge( enemy ) && !vehicleEnemyWasInheritedFromFootCombat ) { //mal: if our current enemy is on foot, more likely to pick a better target. Unless they're defusing our charge, or an enemy we jumped in this vehicle for, then we artificially raise their importance. curEnemyNotInVehicle = true; } numVisEnemies = 1; //mal: our current enemy is always visible to us for ( i = 0; i < MAX_CLIENTS; i++ ) { if ( !ClientIsValid( i, -1 ) ) { continue; //mal: no valid client in this client slot! } if ( i == botNum ) { continue; //mal: dont try to fight ourselves! } if ( i == enemy ) { //mal: ignore an enemy we already have continue; } if ( EnemyIsIgnored( i ) ) { continue; //mal: dont try to fight someone we've flagged to ignore for whatever reason! } //mal: if we're in the middle of a critical obj, dont go looking for trouble, unless they're shooting us! if ( Client_IsCriticalForCurrentObj( botNum, -1.0f ) && ( botInfo->lastAttacker != i || botInfo->lastAttackerTime + 3000 < botWorld->gameLocalInfo.time ) && !ClientIsDefusingOurTeamCharge( i ) ) { continue; } const clientInfo_t& playerInfo = botWorld->clientInfo[ i ]; if ( playerInfo.isNoTarget ) { continue; } //mal: dont target clients that have notarget set - this is useful for debugging, etc. if ( playerInfo.isDisguised && playerInfo.disguisedClient != botNum ) { continue; //mal: won't "see" disguised clients, unless they look like us! } if ( playerInfo.inLimbo ) { continue; } if ( playerInfo.isActor ) { continue; } if ( playerInfo.invulnerableEndTime > botWorld->gameLocalInfo.time ) { continue; //mal: ignore revived/just spawned in clients - get the ppl around them! } if ( playerInfo.health <= 0 ) { continue; } if ( playerInfo.team == botInfo->team ) { continue; } if ( botWorld->gameLocalInfo.botSkill == BOT_SKILL_DEMO && !botWorld->botGoalInfo.gameIsOnFinalObjective && !playerInfo.isBot && enemyPlayerInfo.isBot ) { //mal: dont worry about human targets in training mode if we have a bot one, unless its the final obj... continue; } if ( botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY ) { //mal: st00pid bot - your not smart enough to pick your targets wisely if ( enemyVehicleInfo.entNum > 0 && enemyInfo.enemyVisible ) { if ( !( enemyVehicleInfo.flags & PERSONAL ) && !( enemyVehicleInfo.flags & WATER ) && ( enemyVehicleInfo.isAirborneVehicle && enemyVehicleInfo.xyspeed > 900.0f && entDist > Square( 2000.0f ) ) ) { if ( playerInfo.proxyInfo.entNum == CLIENT_HAS_NO_VEHICLE && !Client_IsCriticalForCurrentObj( i, 1500.0f ) && !ClientHasObj( i ) ) { continue; } //mal: dont worry about an enemy in a vehicle if the vehicle is far away, moving too fast, is not a real threat } } } //mal: if our current enemy is in a vehicle, and this guy isn't, and this guy doesn't have an obj, or isn't important, hes not worth fighting. bool enemyIsInAirAttackVehicle = false; if ( playerInfo.proxyInfo.entNum != CLIENT_HAS_NO_VEHICLE ) { //mal: pick the driver of a vehicle as the target, NOT passengers, unless there is no driver - then kill whoever. GetVehicleInfo( playerInfo.proxyInfo.entNum, vehicleInfo ); if ( vehicleInfo.driverEntNum != i && vehicleInfo.driverEntNum != -1 ) { continue; } if ( vehicleInfo.type == ANANSI || vehicleInfo.type == HORNET ) { enemyIsInAirAttackVehicle = true; } else { vec = vehicleInfo.origin - botInfo->origin; if ( vehicleInfo.xyspeed > 600.0f && vec.LengthSqr() > Square( 1900.0f ) && !InFrontOfVehicle( vehicleInfo.entNum, botInfo->origin ) ) { //mal: if they're in a mad dash away from us, forget about them! continue; } } } vec = playerInfo.origin - botInfo->origin; dist = vec.LengthSqr(); if ( !enemyIsInAirAttackVehicle ) { if ( dist > Square( ENEMY_SIGHT_BUSY_DIST * 2.0f ) ) { continue; } } float tempDist = entDist; if ( curEnemyNotInVehicle && playerInfo.proxyInfo.entNum != CLIENT_HAS_NO_VEHICLE ) { tempDist += Square( 3000.0f ); } if ( !enemyIsInAirAttackVehicle ) { if ( dist > tempDist ) { continue; } } else { if ( dist > Square( AIRCRAFT_ATTACK_DIST ) ) { continue; } } if ( !ClientIsVisibleToBot ( i, true, false ) ) { continue; } if ( Client_IsCriticalForCurrentObj( i, 1500.0f ) && botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY ) { //mal: if a critical class, get high priority dist = Square( 600.0f ); ignoreNewEnemiesWhileInVehicleTime = botWorld->gameLocalInfo.time + IGNORE_NEW_ENEMIES_TIME; } if ( ClientHasObj( i ) && botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY ) { //mal: if have docs, get HIGHER priority. dist = Square( 500.0f ); ignoreNewEnemiesWhileInVehicleTime = botWorld->gameLocalInfo.time + IGNORE_NEW_ENEMIES_TIME; } if ( ClientIsDefusingOurTeamCharge( i ) && botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY ) { //mal: if defusing our charge, get HIGHER priority. dist = Square( 100.0f ); ignoreNewEnemiesWhileInVehicleTime = botWorld->gameLocalInfo.time + IGNORE_NEW_ENEMIES_TIME; } if ( botWorld->botGoalInfo.mapHasMCPGoal && botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY ) { if ( playerInfo.proxyInfo.entNum == botWorld->botGoalInfo.botGoal_MCP_VehicleNum ) { dist = Square( 400.0f ); ignoreNewEnemiesWhileInVehicleTime = botWorld->gameLocalInfo.time + IGNORE_NEW_ENEMIES_TIME; } } if ( enemyIsInAirAttackVehicle && botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY ) { //mal: dont ignore a chance to dogfight! dist = Square( 100.0f ); ignoreNewEnemiesWhileInVehicleTime = botWorld->gameLocalInfo.time + IGNORE_NEW_ENEMIES_TIME; } numVisEnemies++; entClientNum = i; entDist = dist; } if ( entClientNum != enemy ) { enemy = entClientNum; enemySpawnID = botWorld->clientInfo[ entClientNum ].spawnID; enemyInfo.enemy_FS_Pos = botWorld->clientInfo[ entClientNum ].origin; enemyInfo.enemy_LS_Pos = enemyInfo.enemy_FS_Pos; enemyInfo.enemyLastVisTime = botWorld->gameLocalInfo.time; enemyAcquireTime = botWorld->gameLocalInfo.time; bot_FS_Enemy_Pos = botInfo->origin; bot_LS_Enemy_Pos = bot_FS_Enemy_Pos; VEHICLE_COMBAT_AI_SUB_NODE = NULL; //mal: reset the bot's combat AI node and movement state. COMBAT_MOVEMENT_STATE = NULL; return true; } return false; }
/* ================ idBotAI::Bot_CheckVehicleAttack ================ */ void idBotAI::Bot_CheckVehicleAttack() { float minFOV = ( botInfo->proxyInfo.weapon == TANK_GUN ) ? 0.95f : 0.60f; idVec3 dir; if ( botVehicleInfo->type == ICARUS ) { botUcmd->botCmds.attack = true; return; } if ( botInfo->proxyInfo.weapon == NULL_VEHICLE_WEAPON ) { return; } if ( gunTargetEntNum > -1 && gunTargetEntNum < MAX_CLIENTS ) { if ( botWorld->clientInfo[ gunTargetEntNum ].team == botInfo->team && !botWorld->gameLocalInfo.inWarmup ) { return; } } //mal: hold your fire! have a friendly in the way. if ( timeOnTarget > botWorld->gameLocalInfo.time ) { //mal: haven't had time enough to "react" to this threat... return; } if ( !botInfo->proxyInfo.weaponIsReady && botInfo->proxyInfo.weapon == TANK_GUN ) { //mal: strogg hyperblaster will report not ready between shots, which can confuse the bots return; } if ( botInfo->proxyInfo.weapon == PERSONAL_WEAPON ) { if ( enemyInfo.enemyInfont ) { if ( botInfo->weapInfo.weapon == ROCKET ) { if ( botInfo->targetLocked ) { botUcmd->botCmds.attack = true; } } else { botUcmd->botCmds.attack = true; } } return; } if ( botInfo->proxyInfo.weapon == LAW ) { if ( botVehicleInfo->type == TROJAN ) { if ( botWorld->clientInfo[ enemy ].proxyInfo.entNum != CLIENT_HAS_NO_VEHICLE ) { proxyInfo_t enemyVehicle; GetVehicleInfo( botWorld->clientInfo[ enemy ].proxyInfo.entNum, enemyVehicle ); if ( enemyVehicle.type >= ICARUS ) { if ( botInfo->targetLocked ) { botUcmd->botCmds.attack = true; } } else { botUcmd->botCmds.attack = true; } } else { botUcmd->botCmds.attack = true; } } else { if ( botWorld->clientInfo[ enemy ].proxyInfo.entNum != CLIENT_HAS_NO_VEHICLE ) { if ( botInfo->targetLocked ) { botUcmd->botCmds.attack = true; } } } return; } if ( botInfo->proxyInfo.weapon == ROCKETS ) { if ( botVehicleInfo->isAirborneVehicle ) { minFOV = 0.95f; } dir = botWorld->clientInfo[ enemy ].origin - botVehicleInfo->origin; dir.NormalizeFast(); if ( dir * botVehicleInfo->axis[ 0 ] > minFOV ) { //mal: we have them in our sights - FIRE! botUcmd->botCmds.attack = true; } return; } if ( botInfo->proxyInfo.hasTurretWeapon ) { if ( botVehicleInfo->type > ICARUS && botInfo->proxyInfo.weapon == MINIGUN ) { botUcmd->botCmds.attack = true; } else { dir = botWorld->clientInfo[ enemy ].origin - botInfo->proxyInfo.weaponOrigin; dir.NormalizeFast(); if ( dir * botInfo->proxyInfo.weaponAxis[0] > minFOV ) { //mal: we have them in our sights - FIRE! botUcmd->botCmds.attack = true; } } } else { if ( InFrontOfVehicle( botInfo->proxyInfo.entNum, botWorld->clientInfo[ enemy ].origin ) ) { botUcmd->botCmds.attack = true; //mal: they're in front of us - FIRE! } } if ( botWorld->gameLocalInfo.botSkill == BOT_SKILL_EASY && botVehicleInfo->driverEntNum == botNum && botInfo->proxyInfo.weapon != MINIGUN ) { //mal: have a delay between shots for low skill bots. if ( botUcmd->botCmds.attack == true ) { timeOnTarget = botWorld->gameLocalInfo.time + ( ( botVehicleInfo->isAirborneVehicle ) ? 9500 : 5500 ); } } }
/* ================ idBotAI::Bot_VehicleFindEnemy We'll sort thru the clients, and ignore certain clients if we're too busy to be buggered (carrying obj, planting/hacking, etc) or they're not valid enemies (in disguise, hidden by smoke, etc). ================ */ bool idBotAI::Bot_VehicleFindEnemy() { bool hasAttackedMate; bool hasAttackedCriticalMate; bool hasObj; bool isDefusingOurBomb; bool inFront; bool botGotShotRecently; bool botIsBigShot; bool audible; bool isVisible; bool isFacingUs; bool isFiringWeapon; bool isNearOurObj; bool isAttackingDeployable = false; bool inAttackAirCraft = false; int i; int entClientNum = -1; float dist; float botSightDist; float tempSightDist; float entDist = idMath::INFINITY; proxyInfo_t enemyVehicleInfo; enemyVehicleInfo.entNum = 0; idVec3 vec; numVisEnemies = 0; vehicleEnemyWasInheritedFromFootCombat = false; botSightDist = Square( ENEMY_VEHICLE_SIGHT_DIST ); //mal_FIXME: break this out into a script cmd! /* if ( botSightDist > Square( 8000.0f ) ) { botSightDist = Square( 8000.0f ); } else if ( botSightDist < Square( 3000.0f ) ) { botSightDist = Square( 3000.0f ); } */ //mal: some debugging stuff.... if ( botWorld->gameLocalInfo.botIgnoreEnemies == 1 ) { return false; } else if ( botWorld->gameLocalInfo.botIgnoreEnemies == 2 ) { if ( botInfo->team == GDF ) { return false; } } else if ( botWorld->gameLocalInfo.botIgnoreEnemies == 3 ) { if ( botInfo->team == STROGG ) { return false; } } if ( botVehicleInfo->type != BUFFALO && Bot_VehicleIsUnderAVTAttack() != -1 && ( ( botVehicleInfo->flags & ARMOR ) || botVehicleInfo->type > ICARUS ) ) { return false; } if ( botVehicleInfo->type > ICARUS ) { botSightDist = Square( 6000.0f ); } if ( botVehicleInfo->type == BUFFALO ) { botSightDist = Square( 3500.0f ); } if ( botVehicleInfo->type == GOLIATH || botVehicleInfo->type == DESECRATOR ) { //mal: these 2 are really limited botSightDist = Square( PLASMA_CANNON_RANGE - 1000.0f ); } if ( botVehicleInfo->type == HUSKY ) { //mal: we're no match for anybody! return false; } #ifdef _XENON if ( botVehicleInfo->type == MCP && botVehicleInfo->driverEntNum == botNum ) { return false; } if ( botVehicleInfo->type == PLATYPUS && botVehicleInfo->driverEntNum == botNum ) { return false; } #endif if ( botVehicleInfo->type > ICARUS && Client_IsCriticalForCurrentObj( botNum, -1.0f ) ) { return false; } botIsBigShot = Client_IsCriticalForCurrentObj( botNum, 3500.0f ); if ( aiState == VLTG && vLTGType == V_DESTROY_DEPLOYABLE ) { deployableInfo_t deployable; if ( GetDeployableInfo( false, vLTGTarget, deployable ) ) { if ( deployable.type == APT || deployable.type == AVT || deployable.type == AIT ) { //mal: these are the priorities isAttackingDeployable = true; } } } for ( i = 0; i < MAX_CLIENTS; i++ ) { if ( !ClientIsValid( i, -1 ) ) { continue; //mal: no valid client in this client slot! } if ( i == botNum ) { continue; //mal: dont try to fight ourselves! } if ( EnemyIsIgnored( i ) ) { continue; //mal: dont try to fight someone we've flagged to ignore for whatever reason! } if ( !Bot_VehicleCanAttackEnemy( i ) ) { //mal: check if the bot has access to a weapon in the vehicle, that can hit this client. continue; } const clientInfo_t& playerInfo = botWorld->clientInfo[ i ]; if ( playerInfo.isNoTarget ) { continue; } //mal: dont target clients that have notarget set - this is useful for debugging, etc. bool enemyIsBigShot = Client_IsCriticalForCurrentObj( i, 2500.0f ); if ( playerInfo.inLimbo ) { continue; } if ( playerInfo.invulnerableEndTime > botWorld->gameLocalInfo.time ) { continue; //mal: ignore revived/just spawned in clients - get the ppl around them! } if ( playerInfo.isActor ) { continue; } if ( playerInfo.health <= 0 ) { continue; } if ( playerInfo.team == botInfo->team ) { continue; } if ( botVehicleInfo->type == MCP && botVehicleInfo->driverEntNum == botNum ) { if ( !InFrontOfVehicle( botInfo->proxyInfo.entNum, playerInfo.origin ) ) { continue; } } if ( botWorld->gameLocalInfo.botSkill == BOT_SKILL_DEMO && botVehicleInfo->type > ICARUS && !playerInfo.isBot ) { //mal: don't attack human players in training mode when we're in flyers. continue; } hasAttackedCriticalMate = ClientHasAttackedTeammate( i, true, 3000 ); hasAttackedMate = ClientHasAttackedTeammate( i, false, 3000 ); hasObj = ClientHasObj( i ); isDefusingOurBomb = ClientIsDefusingOurTeamCharge( i ); inFront = ( botInfo->proxyInfo.weapon == PERSONAL_WEAPON ) ? InFrontOfClient( botNum, playerInfo.origin) : InFrontOfVehicle( botInfo->proxyInfo.entNum, playerInfo.origin ); isFacingUs = ( playerInfo.proxyInfo.entNum == CLIENT_HAS_NO_VEHICLE ) ? InFrontOfClient( i, botInfo->origin ) : InFrontOfVehicle( playerInfo.proxyInfo.entNum, botInfo->origin ); botGotShotRecently = ( botInfo->lastAttackerTime + 3000 < botWorld->gameLocalInfo.time ) ? false : true; isFiringWeapon = playerInfo.weapInfo.isFiringWeap; isNearOurObj = ( LocationDistFromCurrentObj( botInfo->team, playerInfo.origin ) < 2500.0f ) ? true : false; bool isCriticalEnemy = Client_IsCriticalForCurrentObj( i, 2500.0f ); if ( playerInfo.proxyInfo.entNum != CLIENT_HAS_NO_VEHICLE ) { GetVehicleInfo( playerInfo.proxyInfo.entNum, enemyVehicleInfo ); } if ( isAttackingDeployable ) { if ( botInfo->team == botWorld->botGoalInfo.attackingTeam ) { if ( playerInfo.proxyInfo.entNum == CLIENT_HAS_NO_VEHICLE ) { if ( playerInfo.weapInfo.weapon != ROCKET && !isDefusingOurBomb ) { continue; } } else { if ( !( enemyVehicleInfo.flags & ARMOR ) && enemyVehicleInfo.type != ANANSI && enemyVehicleInfo.type != HORNET ) { continue; } } } else { if ( !isDefusingOurBomb && playerInfo.proxyInfo.entNum == CLIENT_HAS_NO_VEHICLE && !hasObj && playerInfo.weapInfo.weapon != ROCKET && ( !isCriticalEnemy || !isNearOurObj ) ) { continue; } } } if ( botIsBigShot && !isFacingUs && ( !botGotShotRecently || botInfo->lastAttacker != i ) && !isFiringWeapon && !hasObj && !isNearOurObj ) { continue; } //mal: if we're trying to do an important obj, dont get into a fight with everyone. vec = playerInfo.origin - botInfo->origin; if ( botVehicleInfo->isAirborneVehicle ) { vec.z = 0.0f; } dist = vec.LengthSqr(); if ( botIsBigShot && !inFront && dist > Square( 2500.0f ) && ( !botGotShotRecently || botInfo->lastAttacker != i ) && botVehicleInfo->driverEntNum == botNum ) { continue; } if ( playerInfo.proxyInfo.entNum != CLIENT_HAS_NO_VEHICLE ) { //mal: pick the driver of a vehicle as the target, NOT passengers, unless there is no driver - then kill whoever. if ( enemyVehicleInfo.type == ANANSI || enemyVehicleInfo.type == HORNET ) { inAttackAirCraft = true; } if ( botIsBigShot && enemyVehicleInfo.type <= ICARUS ) { continue; } if ( enemyVehicleInfo.type == BUFFALO && botVehicleInfo->flags & ARMOR && playerInfo.isBot ) { continue; } if ( enemyVehicleInfo.type == MCP && enemyVehicleInfo.isImmobilized && enemyVehicleInfo.driverEntNum == i ) { continue; } if ( botVehicleInfo->type == ANANSI && enemyVehicleInfo.type == ICARUS ) { //mal: this is funny to watch, but is a waste of time. :-) continue; } if ( isAttackingDeployable ) { if ( botVehicleInfo->isAirborneVehicle && ( enemyVehicleInfo.type <= ICARUS || enemyVehicleInfo.type == BUFFALO ) ) { //mal: if attacking from the air, only worry about air vehicles. continue; } } if ( enemyVehicleInfo.driverEntNum != i && enemyVehicleInfo.driverEntNum != -1 ) { continue; } if ( inAttackAirCraft && enemyVehicleInfo.xyspeed > 500.0f && dist > Square( TANK_MINIGUN_RANGE ) && botVehicleInfo->flags & ARMOR ) { //mal: tanks won't attack fast moving aircraft that are too far away for their MGs continue; } if ( botVehicleInfo->type == BADGER ) { if ( botInfo->proxyInfo.weapon == NULL_VEHICLE_WEAPON && enemyVehicleInfo.flags & ARMOR || enemyVehicleInfo.inWater || ( enemyVehicleInfo.isAirborneVehicle && dist > Square( 3000.0f ) || enemyVehicleInfo.type == HOG ) ) { continue; } } if ( botVehicleInfo->inWater && botInfo->proxyInfo.weapon == NULL_VEHICLE_WEAPON ) { continue; } if ( botVehicleInfo->type != ANANSI && botVehicleInfo->type != HORNET ) { if ( enemyVehicleInfo.xyspeed > 600.0f && dist > Square( 1900.0f ) && !InFrontOfVehicle( enemyVehicleInfo.entNum, botInfo->origin ) && !ClientHasObj( i ) && !enemyIsBigShot ) { //mal: if they're in a mad dash away from us, forget about them! continue; } } } if ( botVehicleInfo->type == BUFFALO && !inAttackAirCraft ) { //mal_TODO: need to make the buffalo a more effective fighting platform! continue; } tempSightDist = botSightDist; if ( !ClientHasObj( i ) && !enemyIsBigShot && playerInfo.proxyInfo.entNum == CLIENT_HAS_NO_VEHICLE && !playerInfo.isCamper && playerInfo.killsSinceSpawn < KILLING_SPREE && botVehicleInfo->driverEntNum == botNum && !isDefusingOurBomb ) { //mal: vehicles will prefer to fight other vehicles, not some guy on foot a mile away.... tempSightDist = Square( 3500.0f ); } if ( inAttackAirCraft && ( botVehicleInfo->type == ANANSI || botVehicleInfo->type == HORNET ) && botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY ) { tempSightDist = Square( AIRCRAFT_ATTACK_DIST ); } if ( dist > tempSightDist ) { continue; } if ( playerInfo.isDisguised ) { //mal: when in a vehicle, bots are much less likely to notice or worry about coverts if ( botThreadData.GetBotSkill() == BOT_SKILL_EASY ) { continue; } else { if ( ( playerInfo.disguisedClient != botNum && !hasAttackedMate ) || dist > Square( 2500.0f ) ) { continue; } } } if ( !ClientHasObj( i ) ) { audible = ClientIsAudibleToVehicle( i ); //mal: if we can hear you, we'll skip the FOV test in the vis check below } else { audible = true; dist = Square( 500.0f ); //mal: if you've got the docs, your our priority target, unless someone else is right on top of us! } isVisible = ClientIsVisibleToBot( i, !audible, false ); if ( !isVisible && !ClientHasObj( i ) ) { continue; } if ( botWorld->gameLocalInfo.botSkill != BOT_SKILL_DEMO || botWorld->botGoalInfo.gameIsOnFinalObjective || botWorld->botGoalInfo.attackingTeam == botInfo->team ) { if ( isDefusingOurBomb ) { dist = Square( 100.0f ); } if ( hasAttackedCriticalMate && inFront && botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY ) { dist = Square( 600.0f ); //mal: will give higher priority to someone attacking a critical mate, if we can see it happening. } if ( botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY ) { if ( Client_IsCriticalForCurrentObj( i, 6000.0f ) ) { dist = Square( 700.0f ); //mal: if your a critical client, we're more likely to kill you. } } if ( botWorld->botGoalInfo.mapHasMCPGoal ) { if ( playerInfo.proxyInfo.entNum == botWorld->botGoalInfo.botGoal_MCP_VehicleNum ) { dist = 400.0f; } } //mal: if your in MCP, you get higher priority then a normal enemy. Especially when we're in a vehicle! if ( botVehicleInfo->type > ICARUS && botVehicleInfo->type != BUFFALO && ( playerInfo.isCamper || playerInfo.killsSinceSpawn >= KILLING_SPREE ) && botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY && !playerInfo.isBot ) { dist = Square( 600.0f ); } //mal: target trouble making humans! } else { if ( !playerInfo.isBot || playerInfo.isActor ) { dist += Square( TRAINING_MODE_RANGE_ADDITION ); } } numVisEnemies++; if ( dist < entDist ) { entClientNum = i; entDist = dist; } } if ( entClientNum != -1 ) { enemy = entClientNum; enemySpawnID = botWorld->clientInfo[ entClientNum ].spawnID; enemyInfo.enemy_FS_Pos = botWorld->clientInfo[ entClientNum ].origin; enemyInfo.enemy_LS_Pos = enemyInfo.enemy_FS_Pos; bot_FS_Enemy_Pos = botInfo->origin; bot_LS_Enemy_Pos = bot_FS_Enemy_Pos; enemyInfo.enemyLastVisTime = botWorld->gameLocalInfo.time; enemyAcquireTime = botWorld->gameLocalInfo.time; Bot_SetAttackTimeDelay( inFront ); //mal: this sets a delay on how long the bot should take to see enemy, based on bot's state. VEHICLE_COMBAT_AI_SUB_NODE = NULL; //mal: reset the bot's combat AI node COMBAT_MOVEMENT_STATE = NULL; return true; } return false; }
/* ================ idBotAI::Vehicle_Air_To_Air_Movement Air to Air specific attack case. Special case: Air vehicles can't attack one way, while move in another. So they need to have their attack/move unified. This is a bit of a hack, but theres no time to do anything else. :-( ================ */ bool idBotAI::Vehicle_Air_To_Air_Movement() { bool overRideLook = false; bool enemyInFront; bool botInFrontOfEnemy; float desiredRange; float tooCloseDist; float dist; proxyInfo_t enemyVehicleInfo; idVec3 enemyOrg; idVec3 vec; if ( botWorld->clientInfo[ enemy ].proxyInfo.entNum == CLIENT_HAS_NO_VEHICLE ) { Bot_ResetEnemy(); return false; } GetVehicleInfo( botWorld->clientInfo[ enemy ].proxyInfo.entNum, enemyVehicleInfo ); enemyOrg = enemyVehicleInfo.origin; vec = enemyOrg - botVehicleInfo->origin; vec.z = 0.0f; dist = vec.LengthSqr(); float tempDist = vec.LengthFast(); Bot_CheckVehicleAttack(); //mal: always see if we can get a shot off. if ( botInfo->enemyHasLockon && dist < Square( 6000.0f ) && botWorld->gameLocalInfo.botSkill == BOT_SKILL_EASY ) { //mal: OH NOES!1 Panic and run for it. Bot_IgnoreEnemy( enemy, 3000 ); Bot_ResetEnemy(); return false; } if ( botVehicleInfo->type == ANANSI ) { desiredRange = 5000.0f; tooCloseDist = 2500.0f; if ( Bot_CheckEnemyHasLockOn( enemy ) && botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY && botWorld->gameLocalInfo.botSkill != BOT_SKILL_DEMO ) { //mal: they need a bit of an edge botUcmd->botCmds.launchDecoysNow = true; } if ( dist < Square( tooCloseDist ) && combatMoveTime < botWorld->gameLocalInfo.time && botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY ) { combatMoveDir = BACK; combatMoveTime = botWorld->gameLocalInfo.time + 5000; botUcmd->botCmds.launchDecoys = true; //mal: we're exposing our flank, so fire some decoys to cover our move. } if ( combatMoveTime > botWorld->gameLocalInfo.time ) { if ( !InAirVehicleGunSights( enemyVehicleInfo.entNum, botInfo->origin ) ) { //mal: he can't see us anymore, so attack! combatMoveTime = 0; overRideLook = true; } } if ( combatMoveTime > 0 ) { vec = enemyOrg; vec += ( -desiredRange * enemyVehicleInfo.axis[ 0 ] ); if ( !botThreadData.Nav_IsDirectPath( AAS_VEHICLE, botInfo->team, botInfo->areaNumVehicle, botInfo->aasVehicleOrigin, vec ) ) { combatMoveTime = 0; return true; } Bot_SetupVehicleMove( vec, -1, ACTION_NULL ); if ( MoveIsInvalid() ) { combatMoveTime = 0; return true; } Bot_MoveToGoal( botAAS.path.moveGoal, vec3_zero, RUN, NULLMOVETYPE ); Bot_LookAtLocation( botAAS.path.viewGoal, SMOOTH_TURN ); return true; } } else { //must be in a hornet desiredRange = 2500.0f; //mal: was 1500 tooCloseDist = 0.0f; if ( dist < Square( desiredRange ) && combatMoveTime < botWorld->gameLocalInfo.time && botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY ) { int n = botThreadData.random.RandomInt( 3 ); //mal: we're too close, so manuever around our enemy and fire. low skill bots need not apply. if ( n == 0 ) { combatMoveDir = BACK; } else if ( n == 1 ) { combatMoveDir = RIGHT; } else { combatMoveDir = LEFT; } combatMoveTime = botWorld->gameLocalInfo.time + 5000; botUcmd->botCmds.launchDecoys = true; //mal: we're exposing our flank, so fire some decoys to cover our move. } if ( combatMoveTime > botWorld->gameLocalInfo.time ) { if ( !InAirVehicleGunSights( enemyVehicleInfo.entNum, botInfo->origin ) ) { //mal: he can't see us anymore, so attack! combatMoveTime = 0; overRideLook = true; } } if ( combatMoveTime > 0 ) { vec = enemyOrg; if ( combatMoveDir == BACK ) { vec += ( -desiredRange * botInfo->viewAxis[ 0 ] ); //mal: this seems wrong, but it works SO well. } else if ( combatMoveDir == RIGHT ) { vec += ( desiredRange * ( botInfo->viewAxis[ 1 ] * -1 ) ); } else if ( combatMoveDir == LEFT ) { vec += ( -desiredRange * ( botInfo->viewAxis[ 1 ] * -1 ) ); } if ( !botThreadData.Nav_IsDirectPath( AAS_VEHICLE, botInfo->team, botInfo->areaNumVehicle, botInfo->aasVehicleOrigin, vec ) ) { combatMoveTime = 0; return true; } Bot_SetupVehicleMove( vec, -1, ACTION_NULL ); if ( MoveIsInvalid() ) { combatMoveTime = 0; return true; } Bot_MoveToGoal( botAAS.path.moveGoal, vec3_zero, RUN, NULLMOVETYPE ); Bot_LookAtLocation( botAAS.path.viewGoal, SMOOTH_TURN ); return true; } } enemyInFront = InFrontOfVehicle( botVehicleInfo->entNum, enemyOrg ); botInFrontOfEnemy = InFrontOfVehicle( enemyVehicleInfo.entNum, botInfo->origin ); if ( dist > Square( desiredRange ) ) { Bot_SetupVehicleMove( vec3_zero, enemy, ACTION_NULL ); if ( MoveIsInvalid() ) { Bot_IgnoreEnemy( enemy, ENEMY_IGNORE_TIME ); //mal: no valid path to this client for some reason - ignore him for a while Bot_ResetEnemy(); return false; } //mal: if we're just moving into range of the target, we'll try to get a lock. If not ( or in danger ) we'll gun it. Fighter pilot mantra: speed is life. Bot_MoveToGoal( botAAS.path.moveGoal, vec3_zero, RUN, ( botInFrontOfEnemy && enemyInFront && dist > Square( 6000.0f ) && botVehicleInfo->forwardSpeed > 1500.0f && !botInfo->enemyHasLockon ) ? AIR_COAST : NULLMOVETYPE ); if ( enemyInFront || overRideLook ) { Bot_LookAtEntity( enemy, SMOOTH_TURN ); } else { Bot_LookAtLocation( botAAS.path.viewGoal, SMOOTH_TURN ); } } else { Bot_SetupVehicleMove( vec3_zero, enemy, ACTION_NULL ); //mal: still want to take into account obstacles, so do a move check. if ( MoveIsInvalid() ) { Bot_IgnoreEnemy( enemy, ENEMY_IGNORE_TIME ); //mal: no valid path to this client for some reason - ignore him for a while Bot_ResetEnemy(); return false; } Bot_MoveToGoal( botAAS.path.moveGoal, vec3_zero, RUN, ( botAAS.obstacleNum == -1 ) ? AIR_BRAKE : NULLMOVETYPE ); Bot_LookAtEntity( enemy, SMOOTH_TURN ); } return true; }
/* ================ idBotAI::Vehicle_Air_To_Ground_Movement Ground Specific attack case. Special case: Air vehicles can't attack one way, while move in another. So they need to have their attack/move unified. This is a bit of a hack, but theres no time to do anything else. :-( ================ */ bool idBotAI::Vehicle_Air_To_Ground_Movement() { bool overRideLook = false; bool inVehicle = false; float desiredRange = 5800.0f; float tooCloseRange = 2700.0f; float enemySpeed = 0.0f; float dist; proxyInfo_t enemyVehicleInfo; idVec3 enemyOrg; idVec3 vec; if ( botWorld->clientInfo[ enemy ].proxyInfo.entNum != CLIENT_HAS_NO_VEHICLE ) { GetVehicleInfo( botWorld->clientInfo[ enemy ].proxyInfo.entNum, enemyVehicleInfo ); enemyOrg = enemyVehicleInfo.origin; inVehicle = true; } else { enemyOrg = botWorld->clientInfo[ enemy ].origin; } enemySpeed = botWorld->clientInfo[ enemy ].xySpeed; vec = enemyOrg - botVehicleInfo->origin; vec[ 2 ] = 0.0f; dist = vec.LengthSqr(); Bot_CheckVehicleAttack(); //mal: always see if we can get a shot off. if ( botInfo->enemyHasLockon && dist < Square( 6000.0f ) && botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY ) { //mal: OH NOES! Panic and run for it. Bot_IgnoreEnemy( enemy, 3000 ); Bot_ResetEnemy(); return false; } //mal: we're too close, so manuever around our enemy and fire. if ( dist < Square( tooCloseRange ) && combatMoveTime < botWorld->gameLocalInfo.time && enemySpeed < SPRINTING_SPEED ) { //mal: if they're moving fast, just let them move into our crosshairs.. int actionNumber = ACTION_NULL; if ( botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY ) { actionNumber = Bot_FindNearbySafeActionToMoveToward( botInfo->origin, ( desiredRange ) ); } if ( actionNumber != -1 ) { combatMoveActionGoal = actionNumber; combatMoveTime = botWorld->gameLocalInfo.time + 10000; combatMoveTooCloseRange = ( inVehicle ) ? 5000.0f : tooCloseRange + 1000.0f; } else { int n = botThreadData.random.RandomInt( 3 ); if ( n == 0 ) { combatMoveDir = BACK; } else if ( n == 1 ) { combatMoveDir = RIGHT; } else { combatMoveDir = LEFT; } combatMoveTime = botWorld->gameLocalInfo.time + 5000; combatMoveTooCloseRange = tooCloseRange; } } if ( combatMoveTime > botWorld->gameLocalInfo.time ) { if ( dist > Square( combatMoveTooCloseRange ) ) { //mal: we're far enough away to get a shot - attack. combatMoveTime = 0; combatMoveActionGoal = ACTION_NULL; overRideLook = true; } } if ( combatMoveTime > botWorld->gameLocalInfo.time ) { if ( combatMoveActionGoal != ACTION_NULL ) { Bot_SetupVehicleMove( vec3_zero, -1, combatMoveActionGoal ); } else { vec = enemyOrg; if ( combatMoveDir == BACK ) { vec += ( -tooCloseRange * botWorld->clientInfo[ enemy ].viewAxis[ 0 ] ); } else if ( combatMoveDir == RIGHT ) { vec += ( tooCloseRange * ( botWorld->clientInfo[ enemy ].viewAxis[ 1 ] * -1 ) ); } else if ( combatMoveDir == LEFT ) { vec += ( -tooCloseRange * ( botWorld->clientInfo[ enemy ].viewAxis[ 1 ] * -1 ) ); } vec.z = botVehicleInfo->origin.z; if ( !botThreadData.Nav_IsDirectPath( AAS_VEHICLE, botInfo->team, botInfo->areaNumVehicle, botInfo->aasVehicleOrigin, vec ) ) { combatMoveTime = 0; return true; } Bot_SetupVehicleMove( vec, -1, ACTION_NULL ); } if ( MoveIsInvalid() ) { combatMoveTime = 0; combatMoveActionGoal = ACTION_NULL; return true; } Bot_MoveToGoal( botAAS.path.moveGoal, vec3_zero, RUN, NULLMOVETYPE ); Bot_LookAtLocation( botAAS.path.viewGoal, SMOOTH_TURN ); return true; } if ( dist > Square( desiredRange ) ) { Bot_SetupVehicleMove( vec3_zero, enemy, ACTION_NULL ); if ( MoveIsInvalid() ) { Bot_IgnoreEnemy( enemy, ENEMY_IGNORE_TIME ); //mal: no valid path to this client for some reason - ignore him for a while Bot_ResetEnemy(); return false; } Bot_MoveToGoal( botAAS.path.moveGoal, vec3_zero, RUN, NULLMOVETYPE ); if ( InFrontOfVehicle( botVehicleInfo->entNum, enemyOrg ) || overRideLook ) { Bot_LookAtEntity( enemy, SMOOTH_TURN ); } else { Bot_LookAtLocation( botAAS.path.viewGoal, SMOOTH_TURN ); } } else { Bot_SetupVehicleMove( vec3_zero, enemy, ACTION_NULL ); //mal: still want to take into account obstacles, so do a move check. if ( MoveIsInvalid() ) { Bot_IgnoreEnemy( enemy, ENEMY_IGNORE_TIME ); //mal: no valid path to this client for some reason - ignore him for a while Bot_ResetEnemy(); return false; } botMoveTypes_t defaultMoveType = AIR_BRAKE; if ( botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY && Bot_VehicleIsUnderAVTAttack() != -1 || Bot_CheckIfEnemyHasUsInTheirSightsWhenInAirVehicle() || Bot_CheckEnemyHasLockOn( -1, true ) || combatKeepMovingTime > botWorld->gameLocalInfo.time ) { //mal: do a bombing run if someone is shooting at us! defaultMoveType = NULLMOVETYPE; if ( combatKeepMovingTime < botWorld->gameLocalInfo.time ) { combatKeepMovingTime = botWorld->gameLocalInfo.time + FLYER_AVOID_DANGER_TIME; } } Bot_MoveToGoal( botAAS.path.moveGoal, vec3_zero, RUN, ( botAAS.obstacleNum == -1 ) ? defaultMoveType : NULLMOVETYPE ); Bot_LookAtEntity( enemy, SMOOTH_TURN ); } return true; }
void Vehicle::ApplyAllImmunities() { // This couldn't be done in DB, because some spells have MECHANIC_NONE // Vehicles should be immune on Knockback ... _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true); _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK_DEST, true); // Mechanical units & vehicles ( which are not Bosses, they have own immunities in DB ) should be also immune on healing ( exceptions in switch below ) if (_me->ToCreature() && _me->ToCreature()->GetCreatureInfo()->type == CREATURE_TYPE_MECHANICAL && !_me->ToCreature()->isWorldBoss()) { // Heal & dispel ... _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_HEAL, true); _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_HEAL_PCT, true); _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_DISPEL, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_PERIODIC_HEAL, true); // ... Shield & Immunity grant spells ... _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_SCHOOL_IMMUNITY, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_UNATTACKABLE, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_SCHOOL_ABSORB, true); _me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SHIELD, true); _me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_IMMUNE_SHIELD, true); // ... Resistance, Split damage, Change stats ... _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_DAMAGE_SHIELD, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_SPLIT_DAMAGE_PCT, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_RESISTANCE, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_STAT, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, true); } // Different immunities for vehicles goes below switch (GetVehicleInfo()->m_ID) { // code below prevents a bug with movable cannons case 160: // Strand of the Ancients case 244: // Wintergrasp case 510: // Isle of Conquest _me->SetControlled(true, UNIT_STATE_ROOT); // why we need to apply this? we can simple add immunities to slow mechanic in DB _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_DECREASE_SPEED, true); break; // Wintergrasp Siege Engine -- need to remove general knockback immunity here case 117: case 324: _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, false); _me->ApplySpellImmune(0, IMMUNITY_ID, 50652, true); // Ram - used by Wintergrasp Demolisher _me->ApplySpellImmune(0, IMMUNITY_ID, 61391, true); // Typhoon - Rank 1 - Druid talent _me->ApplySpellImmune(0, IMMUNITY_ID, 61390, true); // Typhoon - Rank 2 - Druid talent _me->ApplySpellImmune(0, IMMUNITY_ID, 61388, true); // Typhoon - Rank 3 - Druid talent _me->ApplySpellImmune(0, IMMUNITY_ID, 61387, true); // Typhoon - Rank 4 - Druid talent _me->ApplySpellImmune(0, IMMUNITY_ID, 53227, true); // Typhoon - Rank 5 - Druid talent _me->ApplySpellImmune(0, IMMUNITY_ID, 51490, true); // Thunderstorm - Rank 1 - Shaman talent _me->ApplySpellImmune(0, IMMUNITY_ID, 59156, true); // Thunderstorm - Rank 2 - Shaman talent _me->ApplySpellImmune(0, IMMUNITY_ID, 59158, true); // Thunderstorm - Rank 3 - Shaman talent _me->ApplySpellImmune(0, IMMUNITY_ID, 59159, true); // Thunderstorm - Rank 4 - Shaman talent _me->ApplySpellImmune(0, IMMUNITY_ID, 11113, true); // Blast Wave - Rank 1 - Mage talent _me->ApplySpellImmune(0, IMMUNITY_ID, 13018, true); // Blast Wave - Rank 2 - Mage talent _me->ApplySpellImmune(0, IMMUNITY_ID, 13019, true); // Blast Wave - Rank 3 - Mage talent _me->ApplySpellImmune(0, IMMUNITY_ID, 13020, true); // Blast Wave - Rank 4 - Mage talent _me->ApplySpellImmune(0, IMMUNITY_ID, 13021, true); // Blast Wave - Rank 5 - Mage talent _me->ApplySpellImmune(0, IMMUNITY_ID, 27133, true); // Blast Wave - Rank 6 - Mage talent _me->ApplySpellImmune(0, IMMUNITY_ID, 33933, true); // Blast Wave - Rank 7 - Mage talent _me->ApplySpellImmune(0, IMMUNITY_ID, 42944, true); // Blast Wave - Rank 8 - Mage talent _me->ApplySpellImmune(0, IMMUNITY_ID, 42945, true); // Blast Wave - Rank 9 - Mage talent break; // Wintergrasp Demolisher -- need to remove general knockback immunity here case 106: _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, false); _me->ApplySpellImmune(0, IMMUNITY_ID, 51678, true); // Ram - used by Wintergrasp Siege Engine _me->ApplySpellImmune(0, IMMUNITY_ID, 61391, true); // Typhoon - Rank 1 - Druid talent _me->ApplySpellImmune(0, IMMUNITY_ID, 61390, true); // Typhoon - Rank 2 - Druid talent _me->ApplySpellImmune(0, IMMUNITY_ID, 61388, true); // Typhoon - Rank 3 - Druid talent _me->ApplySpellImmune(0, IMMUNITY_ID, 61387, true); // Typhoon - Rank 4 - Druid talent _me->ApplySpellImmune(0, IMMUNITY_ID, 53227, true); // Typhoon - Rank 5 - Druid talent _me->ApplySpellImmune(0, IMMUNITY_ID, 51490, true); // Thunderstorm - Rank 1 - Shaman talent _me->ApplySpellImmune(0, IMMUNITY_ID, 59156, true); // Thunderstorm - Rank 2 - Shaman talent _me->ApplySpellImmune(0, IMMUNITY_ID, 59158, true); // Thunderstorm - Rank 3 - Shaman talent _me->ApplySpellImmune(0, IMMUNITY_ID, 59159, true); // Thunderstorm - Rank 4 - Shaman talent _me->ApplySpellImmune(0, IMMUNITY_ID, 11113, true); // Blast Wave - Rank 1 - Mage talent _me->ApplySpellImmune(0, IMMUNITY_ID, 13018, true); // Blast Wave - Rank 2 - Mage talent _me->ApplySpellImmune(0, IMMUNITY_ID, 13019, true); // Blast Wave - Rank 3 - Mage talent _me->ApplySpellImmune(0, IMMUNITY_ID, 13020, true); // Blast Wave - Rank 4 - Mage talent _me->ApplySpellImmune(0, IMMUNITY_ID, 13021, true); // Blast Wave - Rank 5 - Mage talent _me->ApplySpellImmune(0, IMMUNITY_ID, 27133, true); // Blast Wave - Rank 6 - Mage talent _me->ApplySpellImmune(0, IMMUNITY_ID, 33933, true); // Blast Wave - Rank 7 - Mage talent _me->ApplySpellImmune(0, IMMUNITY_ID, 42944, true); // Blast Wave - Rank 8 - Mage talent _me->ApplySpellImmune(0, IMMUNITY_ID, 42945, true); // Blast Wave - Rank 9 - Mage talent break; // Battleground Demolisher -- need to remove general knockback immunity here case 158: _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, false); _me->ApplySpellImmune(0, IMMUNITY_ID, 61391, true); // Typhoon - Rank 1 - Druid talent _me->ApplySpellImmune(0, IMMUNITY_ID, 61390, true); // Typhoon - Rank 2 - Druid talent _me->ApplySpellImmune(0, IMMUNITY_ID, 61388, true); // Typhoon - Rank 3 - Druid talent _me->ApplySpellImmune(0, IMMUNITY_ID, 61387, true); // Typhoon - Rank 4 - Druid talent _me->ApplySpellImmune(0, IMMUNITY_ID, 53227, true); // Typhoon - Rank 5 - Druid talent _me->ApplySpellImmune(0, IMMUNITY_ID, 51490, true); // Thunderstorm - Rank 1 - Shaman talent _me->ApplySpellImmune(0, IMMUNITY_ID, 59156, true); // Thunderstorm - Rank 2 - Shaman talent _me->ApplySpellImmune(0, IMMUNITY_ID, 59158, true); // Thunderstorm - Rank 3 - Shaman talent _me->ApplySpellImmune(0, IMMUNITY_ID, 59159, true); // Thunderstorm - Rank 4 - Shaman talent _me->ApplySpellImmune(0, IMMUNITY_ID, 11113, true); // Blast Wave - Rank 1 - Mage talent _me->ApplySpellImmune(0, IMMUNITY_ID, 13018, true); // Blast Wave - Rank 2 - Mage talent _me->ApplySpellImmune(0, IMMUNITY_ID, 13019, true); // Blast Wave - Rank 3 - Mage talent _me->ApplySpellImmune(0, IMMUNITY_ID, 13020, true); // Blast Wave - Rank 4 - Mage talent _me->ApplySpellImmune(0, IMMUNITY_ID, 13021, true); // Blast Wave - Rank 5 - Mage talent _me->ApplySpellImmune(0, IMMUNITY_ID, 27133, true); // Blast Wave - Rank 6 - Mage talent _me->ApplySpellImmune(0, IMMUNITY_ID, 33933, true); // Blast Wave - Rank 7 - Mage talent _me->ApplySpellImmune(0, IMMUNITY_ID, 42944, true); // Blast Wave - Rank 8 - Mage talent _me->ApplySpellImmune(0, IMMUNITY_ID, 42945, true); // Blast Wave - Rank 9 - Mage talent break; default: break; } }
/* ================ idBotAI::Vehicle_Stand_Ground_Movement ================ */ bool idBotAI::Vehicle_Stand_Ground_Movement() { // int result; bool enemyHasVehicle = false; float tooCloseDist = 750.0f; proxyInfo_t enemyVehicleInfo; idVec3 vec; if ( combatMoveFailedCount >= 10 ) { VEHICLE_COMBAT_MOVEMENT_STATE = NULL; return false; } if ( botWorld->clientInfo[ enemy ].proxyInfo.entNum != CLIENT_HAS_NO_VEHICLE ) { GetVehicleInfo( botWorld->clientInfo[ enemy ].proxyInfo.entNum, enemyVehicleInfo ); enemyHasVehicle = true; } if ( combatDangerExists ) { Bot_SetupVehicleQuickMove( botInfo->origin, false ); //mal: just path to itself, if its in an obstacle, it will freak and avoid it. if ( MoveIsInvalid() ) { VEHICLE_COMBAT_MOVEMENT_STATE = NULL; return false; } vec = botAAS.path.moveGoal - botInfo->origin; if ( vec.LengthSqr() > Square( 25.0f ) ) { Bot_MoveToGoal( botAAS.path.moveGoal, vec3_zero, SPRINT, NULLMOVETYPE ); } return true; } if ( botVehicleInfo->type == TROJAN && botVehicleInfo->driverEntNum == botNum ) { if ( !InFrontOfVehicle( botVehicleInfo->entNum, botWorld->clientInfo[ enemy ].origin ) ) { Bot_SetupVehicleMove( vec3_zero, enemy, ACTION_NULL ); if ( MoveIsInvalid() ) { VEHICLE_COMBAT_MOVEMENT_STATE = NULL; return false; } Bot_MoveToGoal( botAAS.path.moveGoal, vec3_zero, RUN, NULLMOVETYPE ); return true; } } /* if ( ( !botInfo->proxyInfo.weaponIsReady && botInfo->proxyInfo.weapon == TANK_GUN ) || combatMoveTime < botWorld->gameLocalInfo.time && !vehicleInfo.inSiegeMode ) { if ( combatMoveDir == NULL_DIR ) { result = botThreadData.random.RandomInt( 4 ); if ( result == 0 ) { combatMoveDir = FORWARD; } else if ( result == 1 ) { combatMoveDir = BACK; } else if ( result == 2 ) { combatMoveDir = RIGHT; } else { combatMoveDir = LEFT; } combatMoveTime = botWorld->gameLocalInfo.time + 2000; } if ( Bot_CanMove( combatMoveDir, 300.0f, true ) ) { Bot_MoveToGoal( botCanMoveGoal, vec3_zero, RUN, NULLMOVETYPE ); } else { combatMoveDir = NULL_DIR; combatMoveFailedCount++; } return true; } */ if ( enemyInfo.enemyDist < tooCloseDist ) { if ( botVehicleInfo->type == GOLIATH ) { const clientInfo_t& enemyPlayer = botWorld->clientInfo[ enemy ]; botUcmd->botCmds.exitSiegeMode = true; if ( enemyPlayer.proxyInfo.entNum == CLIENT_HAS_NO_VEHICLE ) { Bot_MoveToGoal( vec3_zero, vec3_zero, NULLMOVEFLAG, TAUNT_MOVE ); return true; } } if ( enemyInfo.enemyInfont ) { if ( Bot_VehicleCanMove( BACK, 100.0f, true )) { Bot_MoveToGoal( botCanMoveGoal, vec3_zero, REVERSE, NULLMOVETYPE ); } else if ( Bot_VehicleCanMove( RIGHT, 100.0f, true ) ) { Bot_MoveToGoal( botCanMoveGoal, vec3_zero, REVERSE, NULLMOVETYPE ); } else if ( Bot_VehicleCanMove( LEFT, 100.0f, true ) ) { Bot_MoveToGoal( botCanMoveGoal, vec3_zero, REVERSE, NULLMOVETYPE ); } else { combatMoveFailedCount++; } } else { if ( Bot_VehicleCanMove( FORWARD, 100.0f, true )) { Bot_MoveToGoal( botCanMoveGoal, vec3_zero, RUN, NULLMOVETYPE ); } else if ( Bot_VehicleCanMove( RIGHT, 100.0f, true ) ) { Bot_MoveToGoal( botCanMoveGoal, vec3_zero, RUN, NULLMOVETYPE ); } else if ( Bot_VehicleCanMove( LEFT, 100.0f, true ) ) { Bot_MoveToGoal( botCanMoveGoal, vec3_zero, RUN, NULLMOVETYPE ); } else { combatMoveFailedCount++; } } return true; } if ( botVehicleInfo->type == GOLIATH && !botVehicleInfo->inSiegeMode ) { idVec3 enemyOrg = botWorld->clientInfo[ enemy ].origin; trace_t trace; botThreadData.clip->TracePointExt( CLIP_DEBUG_PARMS trace, botVehicleInfo->origin, enemyOrg, BOT_VISIBILITY_TRACE_MASK, GetGameEntity( botNum ), GetGameEntity( botVehicleInfo->entNum ) ); if ( enemyInfo.enemyDist > 1200.0f && trace.fraction == 1.0f ) { botUcmd->botCmds.enterSiegeMode = true; } } else if ( botVehicleInfo->type == DESECRATOR ) { if ( enemyHasVehicle && enemyVehicleInfo.type != TITAN ) { if ( enemyInfo.enemyDist > 1500.0f ) { botUcmd->botCmds.enterSiegeMode = true; } } /* else { if ( combatMoveTime < botWorld->gameLocalInfo.time ) { //mal_NOTE: this just caused more problems then its worth. if ( combatMoveDir == NULL_DIR ) { if ( botThreadData.random.RandomInt( 100 ) > 50 ) { combatMoveDir = RIGHT; } else { combatMoveDir = LEFT; } } else { if ( combatMoveDir == RIGHT ) { combatMoveDir = LEFT; } else { combatMoveDir = RIGHT; } } combatMoveTime = botWorld->gameLocalInfo.time + 5000; } if ( combatMoveDir == RIGHT ) { Bot_MoveToGoal( vec3_zero, vec3_zero, NULLMOVEFLAG, LEAN_RIGHT ); } else { Bot_MoveToGoal( vec3_zero, vec3_zero, NULLMOVEFLAG, LEAN_LEFT ); } return true; } */ } Bot_MoveToGoal( vec3_zero, vec3_zero, NULLMOVEFLAG, FULL_STOP ); //mal: hit the brakes! return true; }
void Vehicle::ApplyAllImmunities() { // This couldn't be done in DB, because some spells have MECHANIC_NONE // Vehicles should be immune on Knockback ... //_me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true); //_me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK_DEST, true); // Mechanical units & vehicles ( which are not Bosses, they have own immunities in DB ) should be also immune on healing ( exceptions in switch below ) if (_me->ToCreature() && _me->ToCreature()->GetCreatureTemplate()->type == CREATURE_TYPE_MECHANICAL && !_me->ToCreature()->isWorldBoss()) { // Heal & dispel ... _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_HEAL, true); _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_HEAL_PCT, true); _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_HEAL_MAX_HEALTH, true); // Xinef _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_DISPEL, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_PERIODIC_HEAL, true); // ... Shield & Immunity grant spells ... _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_SCHOOL_IMMUNITY, true); //_me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_UNATTACKABLE, true); _me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SHIELD, true); _me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_IMMUNE_SHIELD, true); if (_me->GetZoneId() == BATTLEFIELD_WG_ZONEID || _me->ToCreature()->GetDBTableGUIDLow() || (_me->FindMap() && _me->FindMap()->Instanceable())) _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_SCHOOL_ABSORB, true); // ... Resistance, Split damage, Change stats ... _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_DAMAGE_SHIELD, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_SPLIT_DAMAGE_PCT, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_RESISTANCE, true); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_STAT, true); // Taunt _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); _me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, true); } // Different immunities for vehicles goes below switch (GetVehicleInfo()->m_ID) { case 160: //Isle of conquest turret case 244: //Wintergrasp turret case 510: // Isle of Conquest case 452: // Isle of Conquest case 543: // Isle of Conquest //_me->SetControlled(true, UNIT_STATE_ROOT); //me->AddUnitMovementFlag(MOVEMENTFLAG_ROOT); //me->SetSpeed(MOVE_TURN_RATE, 0.7f); //me->SetSpeed(MOVE_PITCH_RATE, 0.7f); //me->m_movementInfo.flags2=59; _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_DECREASE_SPEED, true); break; // Ulduar vehicles, remove immunities used in flame leviathan spells case 335: case 336: case 338: _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, false); _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_SCHOOL_ABSORB, false); break; default: break; } }