diff --git a/evobot/src/NS_Constants.h b/evobot/src/NS_Constants.h index ac16bab..74fb34f 100644 --- a/evobot/src/NS_Constants.h +++ b/evobot/src/NS_Constants.h @@ -132,6 +132,8 @@ const int kGestateBaseArmor = 150; const int kSpitVelocity = 1500; const int kShootCloudVelocity = 1100; const int kAcidRocketVelocity = 2000; +const int kGrenadeForce = 800; +const int kBileBombVelocity = 650; const float kBiteRange = 80.0f; const float kBite2Range = 80.0f; // Lerk bite range diff --git a/evobot/src/bot_commander.cpp b/evobot/src/bot_commander.cpp index dc0d7f8..56c7761 100644 --- a/evobot/src/bot_commander.cpp +++ b/evobot/src/bot_commander.cpp @@ -3069,14 +3069,16 @@ void COMM_SetNextSupportAction(bot_t* CommanderBot, commander_action* Action) { edict_t* PrototypeLab = UTIL_GetNearestStructureOfTypeInLocation(STRUCTURE_MARINE_PROTOTYPELAB, UTIL_GetCommChairLocation(), UTIL_MetresToGoldSrcUnits(15.0f), true, false); + NSStructureType SpecialWeaponToDrop = (UTIL_GetNumWeaponsOfTypeInPlay(WEAPON_MARINE_GL) == 0) ? DEPLOYABLE_ITEM_MARINE_GRENADELAUNCHER : DEPLOYABLE_ITEM_MARINE_HMG; + bool bShouldDropHeavyArmour = false; - bool bShouldDropHMG = false; + bool bShouldDropWeapon = false; bool bShouldDropWelder = false; if (CommanderBot->resources > 100) { bShouldDropHeavyArmour = UTIL_GetItemCountOfTypeInArea(DEPLOYABLE_ITEM_MARINE_HEAVYARMOUR, PrototypeLab->v.origin, UTIL_MetresToGoldSrcUnits(5.0f)) < 3; - bShouldDropHMG = UTIL_GetItemCountOfTypeInArea(DEPLOYABLE_ITEM_MARINE_HMG, AdvArmoury->v.origin, UTIL_MetresToGoldSrcUnits(5.0f)) < 3; + bShouldDropWeapon = UTIL_GetItemCountOfTypeInArea(SpecialWeaponToDrop, AdvArmoury->v.origin, UTIL_MetresToGoldSrcUnits(5.0f)) < 3; bShouldDropWelder = UTIL_GetItemCountOfTypeInArea(DEPLOYABLE_ITEM_MARINE_WELDER, AdvArmoury->v.origin, UTIL_MetresToGoldSrcUnits(5.0f)) < 3; } else @@ -3084,11 +3086,11 @@ void COMM_SetNextSupportAction(bot_t* CommanderBot, commander_action* Action) edict_t* MarineNeedingLoadout = UTIL_GetNearestMarineWithoutFullLoadout(AdvArmoury->v.origin, UTIL_MetresToGoldSrcUnits(10.0f)); int NumHeavyArmour = UTIL_GetItemCountOfTypeInArea(DEPLOYABLE_ITEM_MARINE_HEAVYARMOUR, PrototypeLab->v.origin, UTIL_MetresToGoldSrcUnits(5.0f)); - int NumHMG = UTIL_GetItemCountOfTypeInArea(DEPLOYABLE_ITEM_MARINE_HMG, AdvArmoury->v.origin, UTIL_MetresToGoldSrcUnits(5.0f)); + int NumWeapons = UTIL_GetItemCountOfTypeInArea(SpecialWeaponToDrop, AdvArmoury->v.origin, UTIL_MetresToGoldSrcUnits(5.0f)); int NumWelder = UTIL_GetItemCountOfTypeInArea(DEPLOYABLE_ITEM_MARINE_WELDER, AdvArmoury->v.origin, UTIL_MetresToGoldSrcUnits(5.0f)); bShouldDropHeavyArmour = (!FNullEnt(MarineNeedingLoadout) && !PlayerHasEquipment(MarineNeedingLoadout) && NumHeavyArmour == 0); - bShouldDropHMG = (!FNullEnt(MarineNeedingLoadout) && !PlayerHasSpecialWeapon(MarineNeedingLoadout) && NumHMG == 0); + bShouldDropWeapon = (!FNullEnt(MarineNeedingLoadout) && !PlayerHasSpecialWeapon(MarineNeedingLoadout) && NumWeapons == 0); bShouldDropWelder = (!FNullEnt(MarineNeedingLoadout) && !PlayerHasWeapon(MarineNeedingLoadout, WEAPON_MARINE_WELDER) && NumWelder == 0); } @@ -3102,12 +3104,12 @@ void COMM_SetNextSupportAction(bot_t* CommanderBot, commander_action* Action) return; } - if (bShouldDropHMG) + if (bShouldDropWeapon) { - if (Action->ActionType == ACTION_DEPLOY && Action->StructureToBuild == DEPLOYABLE_ITEM_MARINE_HMG) { return; } + if (Action->ActionType == ACTION_DEPLOY && Action->StructureToBuild == SpecialWeaponToDrop) { return; } Action->ActionType = ACTION_DEPLOY; - Action->StructureToBuild = DEPLOYABLE_ITEM_MARINE_HMG; + Action->StructureToBuild = SpecialWeaponToDrop; Action->BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius(MARINE_REGULAR_NAV_PROFILE, AdvArmoury->v.origin, UTIL_MetresToGoldSrcUnits(5.0f)); return; } diff --git a/evobot/src/bot_marine.cpp b/evobot/src/bot_marine.cpp index 184b7fe..bcf454d 100644 --- a/evobot/src/bot_marine.cpp +++ b/evobot/src/bot_marine.cpp @@ -218,12 +218,46 @@ void BotMarineSetPrimaryTask(bot_t* pBot, bot_task* Task) case BOT_ROLE_ASSAULT: MarineAssaultSetPrimaryTask(pBot, Task); return; + case BOT_ROLE_BOMBARDIER: + MarineBombardierSetPrimaryTask(pBot, Task); + return; default: return; } } +void MarineBombardierSetPrimaryTask(bot_t* pBot, bot_task* Task) +{ + // This is a bit of a hacky way of ensuring bot doesn't fall into a loop of head for hive -> spot offence chamber -> back up to kill it and lose sight -> head for hive + // A better option is to have the bot head for hive and target offence chambers that are along their path rather than base it on sight + if (Task->TaskType == TASK_ATTACK && GetStructureTypeFromEdict(Task->TaskTarget) == STRUCTURE_ALIEN_OFFENCECHAMBER) { return; } + + edict_t* DangerTurret = BotGetNearestDangerTurret(pBot, UTIL_MetresToGoldSrcUnits(15.0f)); + + if (!FNullEnt(DangerTurret)) + { + TASK_SetAttackTask(pBot, Task, DangerTurret, false); + return; + } + + const hive_definition* SiegedHive = UTIL_GetNearestHiveUnderSiege(pBot->pEdict->v.origin); + + if (SiegedHive) + { + TASK_SetAttackTask(pBot, Task, SiegedHive->edict, false); + return; + } + + edict_t* NearestAlienRT = UTIL_GetNearestStructureOfTypeInLocation(STRUCTURE_ALIEN_RESTOWER, UTIL_GetCommChairLocation(), UTIL_MetresToGoldSrcUnits(500.0f), true, true); + + if (!FNullEnt(NearestAlienRT)) + { + TASK_SetAttackTask(pBot, Task, NearestAlienRT, false); + return; + } +} + void BotMarineSetCombatModePrimaryTask(bot_t* pBot, bot_task* Task) { switch (pBot->CurrentRole) @@ -1011,6 +1045,12 @@ bool MarineCombatThink(bot_t* pBot) if (pBot->CurrentEnemy < 0) { return false; } + if (GetBotMarinePrimaryWeapon(pBot) == WEAPON_MARINE_GL) + { + MarineBombardierCombatThink(pBot); + return true; + } + edict_t* CurrentEnemy = pBot->TrackedEnemies[pBot->CurrentEnemy].EnemyEdict; enemy_status* TrackedEnemyRef = &pBot->TrackedEnemies[pBot->CurrentEnemy]; @@ -1042,7 +1082,10 @@ bool MarineCombatThink(bot_t* pBot) else { MoveTo(pBot, Armoury->v.origin, MOVESTYLE_NORMAL); - BotReloadWeapons(pBot); + if (gpGlobals->time - TrackedEnemyRef->LastSeenTime > 5.0f) + { + BotReloadWeapons(pBot); + } } return true; } @@ -1129,7 +1172,10 @@ bool MarineCombatThink(bot_t* pBot) if (LOSCheck == ATTACK_OUTOFRANGE) { MoveTo(pBot, TrackedEnemyRef->LastFloorPosition, MOVESTYLE_NORMAL); - BotReloadWeapons(pBot); + if (gpGlobals->time - TrackedEnemyRef->LastSeenTime > 5.0f) + { + BotReloadWeapons(pBot); + } return true; } @@ -1217,13 +1263,144 @@ bool MarineCombatThink(bot_t* pBot) MoveTo(pBot, RetreatLocation, MOVESTYLE_NORMAL); - BotReloadWeapons(pBot); + if (gpGlobals->time - TrackedEnemyRef->LastSeenTime > 5.0f) + { + BotReloadWeapons(pBot); + } } return true; } +void MarineBombardierCombatThink(bot_t* pBot) +{ + edict_t* pEdict = pBot->pEdict; + + if (pBot->CurrentEnemy < 0) { return; } + + edict_t* CurrentEnemy = pBot->TrackedEnemies[pBot->CurrentEnemy].EnemyEdict; + enemy_status* TrackedEnemyRef = &pBot->TrackedEnemies[pBot->CurrentEnemy]; + + if (!TrackedEnemyRef || FNullEnt(CurrentEnemy) || IsPlayerDead(CurrentEnemy)) { return; } + + if (TrackedEnemyRef->bHasLOS) + { + NSWeapon BestWeapon = BotMarineChooseBestWeapon(pBot, CurrentEnemy); + + BotShootTarget(pBot, BestWeapon, CurrentEnemy); + + if (WeaponCanBeReloaded(BestWeapon) && BotGetCurrentWeaponClipAmmo(pBot) == 0) + { + BotReloadWeapons(pBot); + } + + } + else + { + if (BotGetPrimaryWeaponClipAmmo(pBot) > 0 && gpGlobals->time - TrackedEnemyRef->LastSeenTime < 5.0f) + { + Vector GrenadeLoc = UTIL_GetGrenadeThrowTarget(pBot->pEdict, TrackedEnemyRef->LastSeenLocation, UTIL_MetresToGoldSrcUnits(5.0f), true); + + if (GrenadeLoc != ZERO_VECTOR) + { + BotShootLocation(pBot, WEAPON_MARINE_GL, GrenadeLoc); + return; + } + } + else + { + BotLookAt(pBot, TrackedEnemyRef->LastSeenLocation); + + if (gpGlobals->time - TrackedEnemyRef->LastSeenTime > 3.0f) + { + BotReloadWeapons(pBot); + } + } + } + + bool bNeedHealing = (pBot->pEdict->v.health < 80.0f); + + if (bNeedHealing) + { + edict_t* NearestHealthPack = UTIL_GetNearestItemOfType(DEPLOYABLE_ITEM_MARINE_HEALTHPACK, pBot->pEdict->v.origin, UTIL_MetresToGoldSrcUnits(10.0f)); + + if (!FNullEnt(NearestHealthPack)) + { + float Dist = vDist2DSq(pBot->pEdict->v.origin, NearestHealthPack->v.origin); + float EnemyDist = vDist2DSq(CurrentEnemy->v.origin, NearestHealthPack->v.origin); + + if (Dist < EnemyDist) + { + MoveTo(pBot, NearestHealthPack->v.origin, MOVESTYLE_NORMAL); + return; + } + + } + } + + bool bNeedAmmo = (BotGetPrimaryWeaponAmmoReserve(pBot) < BotGetPrimaryWeaponMaxClipSize(pBot)); + + if (bNeedAmmo) + { + edict_t* NearestAmmoPack = UTIL_GetNearestItemOfType(DEPLOYABLE_ITEM_MARINE_AMMO, pBot->pEdict->v.origin, UTIL_MetresToGoldSrcUnits(10.0f)); + + if (!FNullEnt(NearestAmmoPack)) + { + float Dist = vDist2DSq(pBot->pEdict->v.origin, NearestAmmoPack->v.origin); + float EnemyDist = vDist2DSq(CurrentEnemy->v.origin, NearestAmmoPack->v.origin); + + if (Dist < EnemyDist) + { + MoveTo(pBot, NearestAmmoPack->v.origin, MOVESTYLE_NORMAL); + return; + } + } + } + + edict_t* CoverPlayer = UTIL_GetClosestPlayerOnTeamWithLOS(pBot->pEdict->v.origin, MARINE_TEAM, UTIL_MetresToGoldSrcUnits(10.0f), pBot->pEdict); + + if (FNullEnt(CoverPlayer)) + { + if (TrackedEnemyRef->bHasLOS) + { + MoveTo(pBot, UTIL_GetCommChairLocation(), MOVESTYLE_NORMAL); + } + else + { + BotGuardLocation(pBot, pBot->pEdict->v.origin); + } + + return; + } + + if (vDist2DSq(CoverPlayer->v.origin, CurrentEnemy->v.origin) < vDist2DSq(pBot->pEdict->v.origin, CurrentEnemy->v.origin)) + { + if (vDist2DSq(pBot->pEdict->v.origin, CoverPlayer->v.origin) < sqrf(UTIL_MetresToGoldSrcUnits(3.0f))) + { + Vector MoveDir = UTIL_GetVectorNormal2D(pBot->pEdict->v.origin - CoverPlayer->v.origin); + pBot->desiredMovementDir = MoveDir; + } + else + { + BotGuardLocation(pBot, pBot->pEdict->v.origin); + BotLookAt(pBot, TrackedEnemyRef->LastSeenLocation); + } + + } + else + { + Vector EscapeLocation = pBot->BotNavInfo.TargetDestination; + + if (!EscapeLocation || vDist2DSq(EscapeLocation, TrackedEnemyRef->LastSeenLocation) <= vDist2DSq(CoverPlayer->v.origin, TrackedEnemyRef->LastSeenLocation)) + { + EscapeLocation = UTIL_GetRandomPointOnNavmeshInRadius(MARINE_REGULAR_NAV_PROFILE, CoverPlayer->v.origin, UTIL_MetresToGoldSrcUnits(5.0f)); + } + + MoveTo(pBot, EscapeLocation, MOVESTYLE_HIDE); + } +} + void BotReceiveCommanderOrder(bot_t* pBot, AvHOrderType orderType, AvHUser3 TargetType, Vector destination) { UTIL_ClearBotTask(pBot, &pBot->CommanderTask); @@ -1436,7 +1613,7 @@ void MarineHuntEnemy(bot_t* pBot, enemy_status* TrackedEnemy) { if (TimeSinceLastSighting < 5.0f && vDist3DSq(pBot->pEdict->v.origin, TrackedEnemy->LastSeenLocation) <= sqrf(UTIL_MetresToGoldSrcUnits(10.0f))) { - Vector GrenadeThrowLocation = UTIL_GetGrenadeThrowTarget(pBot, TrackedEnemy->LastSeenLocation, UTIL_MetresToGoldSrcUnits(5.0f)); + Vector GrenadeThrowLocation = UTIL_GetGrenadeThrowTarget(pBot->pEdict, TrackedEnemy->LastSeenLocation, UTIL_MetresToGoldSrcUnits(5.0f), false); if (GrenadeThrowLocation != ZERO_VECTOR) { @@ -1495,7 +1672,6 @@ void MarineCombatModeCheckWantsAndNeeds(bot_t* pBot) pBot->WantsAndNeedsTask.TaskTarget = NearestArmoury; } - } void MarineCheckWantsAndNeeds(bot_t* pBot) diff --git a/evobot/src/bot_marine.h b/evobot/src/bot_marine.h index d33d255..49abf61 100644 --- a/evobot/src/bot_marine.h +++ b/evobot/src/bot_marine.h @@ -17,6 +17,7 @@ void MarineThink(bot_t* pBot); void MarineCombatModeThink(bot_t* pBot); bool MarineCombatThink(bot_t* pBot); +void MarineBombardierCombatThink(bot_t* pBot); void MarineHuntEnemy(bot_t* pBot, enemy_status* TrackedEnemy); @@ -30,6 +31,7 @@ void MarineSetCombatModeSecondaryTask(bot_t* pBot, bot_task* Task); void MarineSweeperSetPrimaryTask(bot_t* pBot, bot_task* Task); void MarineCapperSetPrimaryTask(bot_t* pBot, bot_task* Task); void MarineAssaultSetPrimaryTask(bot_t* pBot, bot_task* Task); +void MarineBombardierSetPrimaryTask(bot_t* pBot, bot_task* Task); void MarineSweeperSetCombatModePrimaryTask(bot_t* pBot, bot_task* Task); void MarineAssaultSetCombatModePrimaryTask(bot_t* pBot, bot_task* Task); diff --git a/evobot/src/bot_math.cpp b/evobot/src/bot_math.cpp index 4c4d9da..2265275 100644 --- a/evobot/src/bot_math.cpp +++ b/evobot/src/bot_math.cpp @@ -391,7 +391,7 @@ float clampi(int input, int inMin, int inMax) Vector GetPitchForProjectile(Vector LaunchPoint, Vector TargetPoint, const float ProjectileSpeed, const float Gravity) { - const Vector FlightDelta = TargetPoint - LaunchPoint; + /*const Vector FlightDelta = TargetPoint - LaunchPoint; const Vector DirXY = UTIL_GetVectorNormal2D(FlightDelta); const float DeltaXY = vSize2D(FlightDelta); @@ -439,10 +439,42 @@ Vector GetPitchForProjectile(Vector LaunchPoint, Vector TargetPoint, const float // final answer! Vector OutTossVelocity = (DirXY * MagXY) + (UP_VECTOR * MagZ * ZSign); - return OutTossVelocity; + return OutTossVelocity;*/ + + double start_x = LaunchPoint.x; + double start_y = LaunchPoint.y; + double start_z = LaunchPoint.z; + double target_x = TargetPoint.x; + double target_y = TargetPoint.y; + double target_z = TargetPoint.z; + + double x = target_x - start_x; + double y = target_y - start_y; + double z = target_z - start_z; + + double range = sqrt(x * x + y * y); + + double discriminant = pow(ProjectileSpeed, 4) - Gravity * (Gravity * pow(range, 2) + 2 * z * pow(ProjectileSpeed, 2)); + + if (discriminant < 0) + { + return ZERO_VECTOR; + } + + double launch_angle = atan((pow(ProjectileSpeed, 2) - sqrt(discriminant)) / (Gravity * range)); + + // Calculate the components of the unit vector + double unit_vector_x = cos(launch_angle) * cos(atan2(y, x)); + double unit_vector_y = cos(launch_angle) * sin(atan2(y, x)); + double unit_vector_z = sin(launch_angle); + + Vector LaunchVector = Vector(unit_vector_x, unit_vector_y, unit_vector_z); + return LaunchVector; } + + void UTIL_AnglesToVector(const Vector angles, Vector* fwd, Vector* right, Vector* up) { g_engfuncs.pfnAngleVectors(angles, (float*)fwd, (float*)right, (float*)up); diff --git a/evobot/src/bot_math.h b/evobot/src/bot_math.h index ca3810f..620a401 100644 --- a/evobot/src/bot_math.h +++ b/evobot/src/bot_math.h @@ -21,7 +21,7 @@ static const Vector FWD_VECTOR = Vector(0.0f, 1.0f, 0.0f); // Normalized "forwar static const float MATH_PI = 3.141592654f; static const float DEGREES_RADIANS_CONV = (MATH_PI / 180.0f); -static const float GOLDSRC_GRAVITY = 800.0f; // Default speed of gravity in GoldSrc units per second squared +static const float GOLDSRC_GRAVITY = 400.0f; // Default speed of gravity in GoldSrc units per second squared // Defines a frustum plane typedef struct _FRUSTUM_PLANE_T diff --git a/evobot/src/bot_navigation.cpp b/evobot/src/bot_navigation.cpp index ece60d3..736c4a9 100644 --- a/evobot/src/bot_navigation.cpp +++ b/evobot/src/bot_navigation.cpp @@ -6408,7 +6408,7 @@ Vector UTIL_GetFurthestVisiblePointOnPath(const bot_t* pBot) return pBot->BotNavInfo.CurrentPath[lastVisiblePathPoint].Location; } -Vector UTIL_GetFurthestVisiblePointOnPath(const Vector ViewerLocation, const bot_path_node* path, const int pathSize) +Vector UTIL_GetFurthestVisiblePointOnPath(const Vector ViewerLocation, const bot_path_node* path, const int pathSize, bool bPrecise) { if (pathSize == 0) { return ZERO_VECTOR; } @@ -6419,7 +6419,71 @@ Vector UTIL_GetFurthestVisiblePointOnPath(const Vector ViewerLocation, const bot if (UTIL_QuickTrace(NULL, ViewerLocation, path[i].Location)) { - return path[i].Location; + if (!bPrecise || i == (pathSize - 1)) + { + return path[i].Location; + } + else + { + Vector FromLoc = path[i].Location; + Vector ToLoc = path[i + 1].Location; + + Vector Dir = UTIL_GetVectorNormal(ToLoc - FromLoc); + + float Dist = vDist3D(FromLoc, ToLoc); + int Steps = (int)floorf(Dist / 50.0f); + + if (Steps == 0) { return FromLoc; } + + Vector FinalView = FromLoc; + Vector ThisView = FromLoc + (Dir * 50.0f); + + for (int i = 0; i < Steps; i++) + { + if (UTIL_QuickTrace(NULL, ViewerLocation, ThisView)) + { + FinalView = ThisView; + } + + ThisView = ThisView + (Dir * 50.0f); + } + + return FinalView; + } + } + else + { + if (bPrecise && i < (pathSize - 1)) + { + Vector FromLoc = path[i].Location; + Vector ToLoc = path[i + 1].Location; + + Vector Dir = UTIL_GetVectorNormal(ToLoc - FromLoc); + + float Dist = vDist3D(FromLoc, ToLoc); + int Steps = (int)floorf(Dist / 50.0f); + + if (Steps == 0) { continue; } + + Vector FinalView = ZERO_VECTOR; + Vector ThisView = FromLoc + (Dir * 50.0f); + + for (int i = 0; i < Steps; i++) + { + if (UTIL_QuickTrace(NULL, ViewerLocation, ThisView)) + { + FinalView = ThisView; + } + + ThisView = ThisView + (Dir * 50.0f); + } + + if (FinalView != ZERO_VECTOR) + { + return FinalView; + } + + } } } diff --git a/evobot/src/bot_navigation.h b/evobot/src/bot_navigation.h index 0ecf09e..ea2f625 100644 --- a/evobot/src/bot_navigation.h +++ b/evobot/src/bot_navigation.h @@ -444,7 +444,7 @@ bool UTIL_PointIsReachable(const int NavProfileIndex, const Vector FromLocation, // If the bot has a path, it will work out how far along the path it can see and return the furthest point. Used so that the bot looks ahead along the path rather than just at its next path point Vector UTIL_GetFurthestVisiblePointOnPath(const bot_t* pBot); // For the given viewer location and path, will return the furthest point along the path the viewer could see -Vector UTIL_GetFurthestVisiblePointOnPath(const Vector ViewerLocation, const bot_path_node* path, const int pathSize); +Vector UTIL_GetFurthestVisiblePointOnPath(const Vector ViewerLocation, const bot_path_node* path, const int pathSize, bool bPrecise); // Returns the nearest nav mesh poly reference for the edict's current world position diff --git a/evobot/src/bot_tactical.cpp b/evobot/src/bot_tactical.cpp index c444fa7..c585dae 100644 --- a/evobot/src/bot_tactical.cpp +++ b/evobot/src/bot_tactical.cpp @@ -4968,6 +4968,8 @@ char* UTIL_BotRoleToChar(const BotRole Role) return "Resource Capper"; case BOT_ROLE_ASSAULT: return "Assault"; + case BOT_ROLE_BOMBARDIER: + return "Bombardier"; default: return "INVALID"; } diff --git a/evobot/src/bot_task.cpp b/evobot/src/bot_task.cpp index 7221d95..4d3ae8b 100644 --- a/evobot/src/bot_task.cpp +++ b/evobot/src/bot_task.cpp @@ -956,7 +956,10 @@ void BotProgressMoveTask(bot_t* pBot, bot_task* Task) if (IsPlayerMarine(pBot->pEdict)) { - BotReloadWeapons(pBot); + if (gpGlobals->time - pBot->LastCombatTime > 5.0f) + { + BotReloadWeapons(pBot); + } } } @@ -1511,7 +1514,10 @@ void MarineProgressBuildTask(bot_t* pBot, bot_task* Task) if (IsPlayerMarine(pBot->pEdict)) { - BotReloadWeapons(pBot); + if (gpGlobals->time - pBot->LastCombatTime > 5.0f) + { + BotReloadWeapons(pBot); + } } if (vDist2DSq(pBot->pEdict->v.origin, Task->TaskTarget->v.origin) < sqrf(UTIL_MetresToGoldSrcUnits(5.0f))) @@ -1525,7 +1531,10 @@ void BotProgressGuardTask(bot_t* pBot, bot_task* Task) { if (IsPlayerMarine(pBot->pEdict)) { - BotReloadWeapons(pBot); + if (gpGlobals->time - pBot->LastCombatTime > 5.0f) + { + BotReloadWeapons(pBot); + } } if (vDist2DSq(pBot->pEdict->v.origin, Task->TaskLocation) > sqrf(UTIL_MetresToGoldSrcUnits(5.0f))) @@ -2096,7 +2105,7 @@ void AlienProgressCapResNodeTask(bot_t* pBot, bot_task* Task) void BotProgressTask(bot_t* pBot, bot_task* Task) { - if (!Task) { return; } + if (!Task || Task->TaskType == TASK_NONE) { return; } switch (Task->TaskType) { @@ -2327,7 +2336,10 @@ void MarineProgressCapResNodeTask(bot_t* pBot, bot_task* Task) { MoveTo(pBot, Task->TaskLocation, MOVESTYLE_NORMAL); - BotReloadWeapons(pBot); + if (gpGlobals->time - pBot->LastCombatTime > 5.0f) + { + BotReloadWeapons(pBot); + } return; } @@ -2616,6 +2628,8 @@ char* UTIL_TaskTypeToChar(const BotTaskType TaskType) return "Reinforce Structure"; case TASK_SECURE_HIVE: return "Secure Hive"; + case TASK_PLACE_MINE: + return "Place Mine"; default: return "INVALID"; } diff --git a/evobot/src/bot_util.cpp b/evobot/src/bot_util.cpp index b097963..7076d4b 100644 --- a/evobot/src/bot_util.cpp +++ b/evobot/src/bot_util.cpp @@ -763,9 +763,7 @@ void BotShootLocation(bot_t* pBot, NSWeapon AttackWeapon, const Vector TargetLoc if (CurrentWeapon == WEAPON_MARINE_GL || CurrentWeapon == WEAPON_MARINE_GRENADE) { Vector AimLocation = TargetLocation; - Vector NewAimAngle = GetPitchForProjectile(pBot->CurrentEyePosition, AimLocation, 800.0f, 640.0f); - - NewAimAngle = UTIL_GetVectorNormal(NewAimAngle); + Vector NewAimAngle = GetPitchForProjectile(pBot->CurrentEyePosition, AimLocation, UTIL_GetProjectileVelocityForWeapon(CurrentWeapon), GOLDSRC_GRAVITY); AimLocation = pBot->CurrentEyePosition + (NewAimAngle * 200.0f); @@ -809,6 +807,7 @@ void BotShootLocation(bot_t* pBot, NSWeapon AttackWeapon, const Vector TargetLoc float AimDot = UTIL_GetDotProduct(AimDir, TargetAimDir); float MinAcceptableAccuracy = (CurrentWeapon == WEAPON_LERK_SPORES || CurrentWeapon == WEAPON_LERK_UMBRA) ? 0.8f : 0.9f; + if (CurrentWeapon == WEAPON_MARINE_GRENADE || CurrentWeapon == WEAPON_MARINE_GL) { MinAcceptableAccuracy = 0.95f; } if (AimDot >= MinAcceptableAccuracy) { @@ -940,11 +939,9 @@ void BotShootTarget(bot_t* pBot, NSWeapon AttackWeapon, edict_t* Target) { Vector AimLocation = UTIL_GetCentreOfEntity(Target); - float ProjectileVelocity = (CurrentWeapon == WEAPON_GORGE_BILEBOMB) ? 750.0f : 800.0f; - - Vector NewAimAngle = GetPitchForProjectile(pBot->CurrentEyePosition, AimLocation, ProjectileVelocity, 640.0f); + float ProjectileVelocity = UTIL_GetProjectileVelocityForWeapon(CurrentWeapon); - NewAimAngle = UTIL_GetVectorNormal(NewAimAngle); + Vector NewAimAngle = GetPitchForProjectile(pBot->CurrentEyePosition, AimLocation, ProjectileVelocity, GOLDSRC_GRAVITY); AimLocation = pBot->CurrentEyePosition + (NewAimAngle * 200.0f); @@ -1012,6 +1009,58 @@ void BotShootTarget(bot_t* pBot, NSWeapon AttackWeapon, edict_t* Target) } } +void BombardierAttackTarget(bot_t* pBot, edict_t* Target) +{ + edict_t* DangerTurret = BotGetNearestDangerTurret(pBot, UTIL_MetresToGoldSrcUnits(15.0f)); + + edict_t* BombTarget = (!FNullEnt(DangerTurret)) ? DangerTurret : Target; + + if (!IsBotReloading(pBot)) + { + if (vDist3DSq(pBot->pEdict->v.origin, BombTarget->v.origin) < sqrf(UTIL_MetresToGoldSrcUnits(5.0f))) + { + Vector BackDir = UTIL_GetVectorNormal2D(pBot->pEdict->v.origin - BombTarget->v.origin); + pBot->desiredMovementDir = BackDir; + } + + Vector GrenadeLoc = UTIL_GetGrenadeThrowTarget(pBot->pEdict, BombTarget->v.origin, UTIL_MetresToGoldSrcUnits(5.0f), true); + + if (GrenadeLoc != ZERO_VECTOR) + { + BotShootLocation(pBot, WEAPON_MARINE_GL, GrenadeLoc); + } + else + { + Vector AttackPoint = BombTarget->v.origin; + + if (GetStructureTypeFromEdict(BombTarget) == STRUCTURE_ALIEN_HIVE) + { + const hive_definition* HiveDefinition = UTIL_GetHiveFromEdict(BombTarget); + + if (HiveDefinition) + { + AttackPoint = HiveDefinition->FloorLocation; + } + } + + MoveTo(pBot, AttackPoint, MOVESTYLE_NORMAL); + } + + return; + } + + // Back off to reload + if (GetStructureTypeFromEdict(BombTarget) == STRUCTURE_ALIEN_OFFENCECHAMBER && UTIL_QuickTrace(pBot->pEdict, pBot->CurrentEyePosition, UTIL_GetCentreOfEntity(BombTarget))) + { + BotLookAt(pBot, BombTarget); + MoveTo(pBot, UTIL_GetCommChairLocation(), MOVESTYLE_NORMAL); + return; + } + + + +} + void BotAttackTarget(bot_t* pBot, edict_t* Target) { if (FNullEnt(Target) || (Target->v.deadflag != DEAD_NO)) { return; } @@ -1027,6 +1076,14 @@ void BotAttackTarget(bot_t* pBot, edict_t* Target) Weapon = BotAlienChooseBestWeaponForStructure(pBot, Target); } + // Add special logic for grenade launchers since they aren't used like regular marine hitscan weapons + // This will handle things like firing from around corners, making sure they have cover from allies etc. + if (Weapon == WEAPON_MARINE_GL) + { + BombardierAttackTarget(pBot, Target); + return; + } + BotAttackResult AttackResult = PerformAttackLOSCheck(pBot, Weapon, Target); float WeaponRange = GetMaxIdealWeaponRange(Weapon); @@ -1070,7 +1127,10 @@ void BotAttackTarget(bot_t* pBot, edict_t* Target) if (IsPlayerMarine(pBot->pEdict)) { - BotReloadWeapons(pBot); + if (gpGlobals->time - pBot->LastCombatTime > 5.0f) + { + BotReloadWeapons(pBot); + } } return; @@ -1156,9 +1216,9 @@ void BotReloadWeapons(bot_t* pBot) if (CurrentWeapon == PrimaryWeapon) { BotReloadCurrentWeapon(pBot); - - return; } + + return; } if (WeaponCanBeReloaded(SecondaryWeapon) && BotGetSecondaryWeaponClipAmmo(pBot) < BotGetSecondaryWeaponMaxClipSize(pBot) && BotGetSecondaryWeaponAmmoReserve(pBot) > 0) @@ -1168,17 +1228,14 @@ void BotReloadWeapons(bot_t* pBot) if (CurrentWeapon == SecondaryWeapon) { BotReloadCurrentWeapon(pBot); - return; } + return; } } } void BotThrowGrenadeAtTarget(bot_t* pBot, const Vector TargetPoint) { - float ProjectileSpeed = 800.0f; - float ProjectileGravity = 640.0f; - if (PlayerHasWeapon(pBot->pEdict, WEAPON_MARINE_GL) && (BotGetPrimaryWeaponClipAmmo(pBot) > 0 || BotGetPrimaryWeaponAmmoReserve(pBot) > 0)) { pBot->DesiredCombatWeapon = WEAPON_MARINE_GL; @@ -1194,14 +1251,8 @@ void BotThrowGrenadeAtTarget(bot_t* pBot, const Vector TargetPoint) return; } - if (pBot->DesiredCombatWeapon == WEAPON_MARINE_GL) - { - // I *think* the grenade launcher projectiles have lower gravity than a thrown grenade, but the same velocity. - // Lower gravity means the bot has to aim lower as it has a flatter arc. Seems to work in practice anyway... - ProjectileGravity = 400.0f; - } - Vector ThrowAngle = GetPitchForProjectile(pBot->CurrentEyePosition, TargetPoint, ProjectileSpeed, ProjectileGravity); + Vector ThrowAngle = GetPitchForProjectile(pBot->CurrentEyePosition, TargetPoint, UTIL_GetProjectileVelocityForWeapon(GetBotCurrentWeapon(pBot)), GOLDSRC_GRAVITY); ThrowAngle = UTIL_GetVectorNormal(ThrowAngle); @@ -1252,7 +1303,7 @@ bool IsBotWeaponPlayingReloadAnimation(bot_t* pBot) case WEAPON_MARINE_HMG: return pBot->pEdict->v.weaponanim == 3; case WEAPON_MARINE_GL: - return (pBot->pEdict->v.weaponanim == 1 || pBot->pEdict->v.weaponanim == 2 || pBot->pEdict->v.weaponanim == 4 || pBot->pEdict->v.weaponanim == 5 || pBot->pEdict->v.weaponanim == 6 || pBot->pEdict->v.weaponanim == 7); + return (pBot->pEdict->v.weaponanim >= 1 && pBot->pEdict->v.weaponanim <= 7); default: return false; } @@ -2312,22 +2363,42 @@ void DroneThink(bot_t* pBot) void CustomThink(bot_t* pBot) { - pBot->CurrentEnemy = BotGetNextEnemyTarget(pBot); + if (IsPlayerAlien(pBot->pEdict)) { return; } - if (pBot->CurrentEnemy > -1) + if (!PlayerHasWeapon(pBot->pEdict, WEAPON_MARINE_GL)) { - pBot->LastCombatTime = gpGlobals->time; - - if (IsPlayerMarine(pBot->pEdict)) + if (pBot->PrimaryBotTask.TaskType != TASK_GET_WEAPON) { - MarineThink(pBot); + edict_t* GL = UTIL_GetNearestItemOfType(DEPLOYABLE_ITEM_MARINE_GRENADELAUNCHER, pBot->pEdict->v.origin, UTIL_MetresToGoldSrcUnits(50.0f)); + + if (!FNullEnt(GL)) + { + pBot->PrimaryBotTask.TaskType = TASK_GET_WEAPON; + pBot->PrimaryBotTask.TaskTarget = GL; + pBot->PrimaryBotTask.TaskLocation = GL->v.origin; + } } - else + } + else + { + if (pBot->PrimaryBotTask.TaskType != TASK_ATTACK) { - AlienThink(pBot); + const hive_definition* Hive = UTIL_GetNearestHiveOfStatus(pBot->pEdict->v.origin, HIVE_STATUS_BUILT); + + if (Hive) + { + TASK_SetAttackTask(pBot, &pBot->PrimaryBotTask, Hive->edict, false); + } } } + if (!UTIL_IsTaskStillValid(pBot, &pBot->PrimaryBotTask)) + { + UTIL_ClearBotTask(pBot, &pBot->PrimaryBotTask); + } + + BotProgressTask(pBot, &pBot->PrimaryBotTask); + } void TestAimThink(bot_t* pBot) diff --git a/evobot/src/bot_weapons.cpp b/evobot/src/bot_weapons.cpp index bc40794..d04c843 100644 --- a/evobot/src/bot_weapons.cpp +++ b/evobot/src/bot_weapons.cpp @@ -40,6 +40,11 @@ float UTIL_GetProjectileVelocityForWeapon(const NSWeapon Weapon) return (float)kShootCloudVelocity; case WEAPON_FADE_ACIDROCKET: return (float)kAcidRocketVelocity; + case WEAPON_GORGE_BILEBOMB: + return (float)kBileBombVelocity; + case WEAPON_MARINE_GRENADE: + case WEAPON_MARINE_GL: + return (float)kGrenadeForce; default: return 0.0f; // Hitscan. We don't bother with bile bomb as it's so short range that it doesn't really need leading the target } @@ -427,16 +432,16 @@ NSWeapon GetBotAlienPrimaryWeapon(const bot_t* pBot) return WEAPON_NONE; } -Vector UTIL_GetGrenadeThrowTarget(bot_t* pBot, const Vector TargetLocation, const float ExplosionRadius) +Vector UTIL_GetGrenadeThrowTarget(edict_t* Player, const Vector TargetLocation, const float ExplosionRadius, bool bPrecise) { - if (UTIL_PlayerHasLOSToLocation(pBot->pEdict, TargetLocation, UTIL_MetresToGoldSrcUnits(10.0f))) + if (UTIL_PlayerHasLOSToLocation(Player, TargetLocation, UTIL_MetresToGoldSrcUnits(10.0f))) { return TargetLocation; } - if (UTIL_PointIsDirectlyReachable(pBot->pEdict->v.origin, TargetLocation)) + if (UTIL_PointIsDirectlyReachable(Player->v.origin, TargetLocation)) { - Vector Orientation = UTIL_GetVectorNormal(pBot->pEdict->v.origin - TargetLocation); + Vector Orientation = UTIL_GetVectorNormal(Player->v.origin - TargetLocation); Vector NewSpot = TargetLocation + (Orientation * UTIL_MetresToGoldSrcUnits(1.5f)); @@ -453,18 +458,18 @@ Vector UTIL_GetGrenadeThrowTarget(bot_t* pBot, const Vector TargetLocation, cons bot_path_node CheckPath[MAX_PATH_SIZE]; int PathSize = 0; - dtStatus Status = FindPathClosestToPoint(ALL_NAV_PROFILE, pBot->pEdict->v.origin, TargetLocation, CheckPath, &PathSize, ExplosionRadius); + dtStatus Status = FindPathClosestToPoint(ALL_NAV_PROFILE, Player->v.origin, TargetLocation, CheckPath, &PathSize, ExplosionRadius); if (dtStatusSucceed(Status)) { - Vector FurthestPointVisible = UTIL_GetFurthestVisiblePointOnPath(pBot->CurrentEyePosition, CheckPath, PathSize); + Vector FurthestPointVisible = UTIL_GetFurthestVisiblePointOnPath(GetPlayerEyePosition(Player), CheckPath, PathSize, bPrecise); if (vDist3DSq(FurthestPointVisible, TargetLocation) <= sqrf(ExplosionRadius)) { return FurthestPointVisible; } - Vector ThrowDir = UTIL_GetVectorNormal(FurthestPointVisible - pBot->pEdict->v.origin); + Vector ThrowDir = UTIL_GetVectorNormal(FurthestPointVisible - Player->v.origin); Vector LineEnd = FurthestPointVisible + (ThrowDir * UTIL_MetresToGoldSrcUnits(5.0f)); @@ -473,7 +478,7 @@ Vector UTIL_GetGrenadeThrowTarget(bot_t* pBot, const Vector TargetLocation, cons ClosestPointInTrajectory = UTIL_ProjectPointToNavmesh(ClosestPointInTrajectory); ClosestPointInTrajectory.z += 10.0f; - if (vDist2DSq(ClosestPointInTrajectory, TargetLocation) < sqrf(ExplosionRadius) && UTIL_PlayerHasLOSToLocation(pBot->pEdict, ClosestPointInTrajectory, UTIL_MetresToGoldSrcUnits(10.0f)) && UTIL_PointIsDirectlyReachable(ClosestPointInTrajectory, TargetLocation)) + if (vDist2DSq(ClosestPointInTrajectory, TargetLocation) < sqrf(ExplosionRadius) && UTIL_PlayerHasLOSToLocation(Player, ClosestPointInTrajectory, UTIL_MetresToGoldSrcUnits(10.0f)) && UTIL_PointIsDirectlyReachable(ClosestPointInTrajectory, TargetLocation)) { return ClosestPointInTrajectory; } @@ -491,7 +496,7 @@ Vector UTIL_GetGrenadeThrowTarget(bot_t* pBot, const Vector TargetLocation, cons NSWeapon BotMarineChooseBestWeapon(bot_t* pBot, edict_t* target) { - if (!target) + if (FNullEnt(target)) { if (BotGetPrimaryWeaponClipAmmo(pBot) > 0 || BotGetPrimaryWeaponAmmoReserve(pBot) > 0) { @@ -511,6 +516,21 @@ NSWeapon BotMarineChooseBestWeapon(bot_t* pBot, edict_t* target) { float DistFromEnemy = vDist2DSq(pBot->pEdict->v.origin, target->v.origin); + if (GetBotMarinePrimaryWeapon(pBot) == WEAPON_MARINE_GL) + { + if (BotGetPrimaryWeaponClipAmmo(pBot) > 0 && DistFromEnemy > sqrf(UTIL_MetresToGoldSrcUnits(5.0f))) + { + return WEAPON_MARINE_GL; + } + + if (BotGetSecondaryWeaponClipAmmo(pBot) > 0) + { + return GetBotMarineSecondaryWeapon(pBot); + } + + return WEAPON_MARINE_KNIFE; + } + if (DistFromEnemy <= sqrf(UTIL_MetresToGoldSrcUnits(2.0f))) { if (BotGetPrimaryWeaponClipAmmo(pBot) == 0) diff --git a/evobot/src/bot_weapons.h b/evobot/src/bot_weapons.h index 3c5ba6d..8e20e3a 100644 --- a/evobot/src/bot_weapons.h +++ b/evobot/src/bot_weapons.h @@ -35,7 +35,7 @@ float GetMinIdealWeaponRange(const NSWeapon Weapon); bool WeaponCanBeReloaded(const NSWeapon CheckWeapon); bool IsMeleeWeapon(const NSWeapon Weapon); -Vector UTIL_GetGrenadeThrowTarget(bot_t* pBot, const Vector TargetLocation, const float ExplosionRadius); +Vector UTIL_GetGrenadeThrowTarget(edict_t* Player, const Vector TargetLocation, const float ExplosionRadius, bool bPrecise); NSWeapon BotMarineChooseBestWeaponForStructure(bot_t* pBot, edict_t* target); NSWeapon BotAlienChooseBestWeaponForStructure(bot_t* pBot, edict_t* target); diff --git a/evobot/src/dllapi.cpp b/evobot/src/dllapi.cpp index 32cd209..604144b 100644 --- a/evobot/src/dllapi.cpp +++ b/evobot/src/dllapi.cpp @@ -48,6 +48,7 @@ #include "bot_task.h" #include "bot_bsp.h" #include "bot_commander.h" +#include "bot_weapons.h" extern int m_spriteTexture; @@ -144,13 +145,22 @@ void ClientCommand(edict_t* pEntity) RETURN_META(MRES_SUPERCEDE); } - if (FStrEq(pcmd, "testbackpath")) + if (FStrEq(pcmd, "grenadetest")) { - Vector Result = DEBUG_FindClosestPointBackOnPath(pEntity); + edict_t* ResTower = UTIL_GetNearestStructureOfTypeInLocation(STRUCTURE_ALIEN_OFFENCECHAMBER, pEntity->v.origin, UTIL_MetresToGoldSrcUnits(500.0f), true, false); - if (Result != ZERO_VECTOR) + if (!FNullEnt(ResTower)) { - UTIL_DrawLine(pEntity, pEntity->v.origin, Result, 5.0f); + Vector GrenLoc = UTIL_GetGrenadeThrowTarget(pEntity, ResTower->v.origin, UTIL_MetresToGoldSrcUnits(3.0f), true); + + if (GrenLoc != ZERO_VECTOR) + { + UTIL_DrawLine(pEntity, pEntity->v.origin, GrenLoc, 10.0f); + } + else + { + UTIL_SayText("No Grenade Location\n", pEntity); + } } RETURN_META(MRES_SUPERCEDE); diff --git a/evobot/src/meta_api.cpp b/evobot/src/meta_api.cpp index 67af262..7182f42 100644 --- a/evobot/src/meta_api.cpp +++ b/evobot/src/meta_api.cpp @@ -62,7 +62,7 @@ static META_FUNCTIONS gMetaFunctionTable = { plugin_info_t Plugin_info = { META_INTERFACE_VERSION, // ifvers "Evobot", // name - "1.0.0", // version + "1.1.0", // version __DATE__, // date "Richard Greenlees", // author "https://github.com/RGreenlees/evobot_mm", // url