/** * @brief Run base defences. * @param[in] dt Time elapsed since last call of this function. */ void AIRFIGHT_CampaignRunBaseDefence (int dt) { base_t* base; base = nullptr; while ((base = B_GetNext(base)) != nullptr) { int idx; if (B_IsUnderAttack(base)) continue; for (idx = 0; idx < base->numBatteries; idx++) { baseWeapon_t* battery = &base->batteries[idx]; aircraftSlot_t* slot = &battery->slot; if (slot->delayNextShot > 0) slot->delayNextShot -= dt; if (slot->ammoLeft <= 0) AII_ReloadWeapon(slot); } for (idx = 0; idx < base->numLasers; idx++) { baseWeapon_t* battery = &base->lasers[idx]; aircraftSlot_t* slot = &battery->slot; if (slot->delayNextShot > 0) slot->delayNextShot -= dt; if (slot->ammoLeft <= 0) AII_ReloadWeapon(slot); } if (AII_BaseCanShoot(base)) { if (B_GetBuildingStatus(base, B_DEFENCE_MISSILE)) AIRFIGHT_BaseShoot(base, base->batteries, base->numBatteries); if (B_GetBuildingStatus(base, B_DEFENCE_LASER)) AIRFIGHT_BaseShoot(base, base->lasers, base->numLasers); } } INS_Foreach(installation) { if (installation->installationStatus != INSTALLATION_WORKING) continue; if (installation->installationTemplate->maxBatteries <= 0) continue; for (int idx = 0; idx < installation->installationTemplate->maxBatteries; idx++) { baseWeapon_t* battery = &installation->batteries[idx]; aircraftSlot_t* slot = &battery->slot; if (slot->delayNextShot > 0) slot->delayNextShot -= dt; if (slot->ammoLeft <= 0) AII_ReloadWeapon(slot); } if (AII_InstallationCanShoot(installation)) { AIRFIGHT_InstallationShoot(installation, installation->batteries, installation->installationTemplate->maxBatteries); } } }
/** * @brief Add a projectile in ccs.projectiles * @param[in] attackingBase the attacking base in ccs.bases[]. NULL is the attacker is an aircraft or a samsite. * @param[in] attackingInstallation the attacking samsite in ccs.installations[]. NULL is the attacker is an aircraft or a base. * @param[in] attacker Pointer to the attacking aircraft * @param[in] target Pointer to the target aircraft * @param[in] weaponSlot Pointer to the weapon slot that fires the projectile. * @note we already checked in AIRFIGHT_ChooseWeapon that the weapon has still ammo * @sa AIRFIGHT_RemoveProjectile * @sa AII_ReloadWeapon for the aircraft item reload code */ static qboolean AIRFIGHT_AddProjectile (const base_t* attackingBase, const installation_t* attackingInstallation, aircraft_t *attacker, aircraft_t *target, aircraftSlot_t *weaponSlot) { aircraftProjectile_t *projectile; if (ccs.numProjectiles >= MAX_PROJECTILESONGEOSCAPE) { Com_DPrintf(DEBUG_CLIENT, "Too many projectiles on map\n"); return qfalse; } projectile = &ccs.projectiles[ccs.numProjectiles]; if (!weaponSlot->ammo) { Com_Printf("AIRFIGHT_AddProjectile: Error - no ammo assigned\n"); return qfalse; } assert(weaponSlot->item); projectile->aircraftItem = weaponSlot->ammo; if (attackingBase) { projectile->attackingAircraft = NULL; VectorSet(projectile->pos[0], attackingBase->pos[0], attackingBase->pos[1], 0); VectorSet(projectile->attackerPos, attackingBase->pos[0], attackingBase->pos[1], 0); } else if (attackingInstallation) { projectile->attackingAircraft = NULL; VectorSet(projectile->pos[0], attackingInstallation->pos[0], attackingInstallation->pos[1], 0); VectorSet(projectile->attackerPos, attackingInstallation->pos[0], attackingInstallation->pos[1], 0); } else { assert(attacker); projectile->attackingAircraft = attacker; VectorSet(projectile->pos[0], attacker->pos[0], attacker->pos[1], 0); /* attacker may move, use attackingAircraft->pos */ VectorSet(projectile->attackerPos, 0, 0, 0); } projectile->numProjectiles++; assert(target); projectile->aimedAircraft = target; VectorSet(projectile->idleTarget, 0, 0, 0); projectile->time = 0; projectile->angle = 0.0f; projectile->bullets = (weaponSlot->item->craftitem.bullets) ? qtrue : qfalse; projectile->beam = (weaponSlot->item->craftitem.beam) ? qtrue : qfalse; weaponSlot->ammoLeft--; if (weaponSlot->ammoLeft <= 0) AII_ReloadWeapon(weaponSlot); ccs.numProjectiles++; return qtrue; }
/** * @brief Add a projectile in ccs.projectiles * @param[in] attackingBase the attacking base in ccs.bases[]. nullptr is the attacker is an aircraft or a samsite. * @param[in] attackingInstallation the attacking samsite in ccs.installations[]. nullptr is the attacker is an aircraft or a base. * @param[in] attacker Pointer to the attacking aircraft * @param[in] target Pointer to the target aircraft * @param[in] weaponSlot Pointer to the weapon slot that fires the projectile. * @note we already checked in AIRFIGHT_ChooseWeapon that the weapon has still ammo * @sa AIRFIGHT_RemoveProjectile * @sa AII_ReloadWeapon for the aircraft item reload code */ static bool AIRFIGHT_AddProjectile (const base_t* attackingBase, const installation_t* attackingInstallation, aircraft_t* attacker, aircraft_t* target, aircraftSlot_t* weaponSlot) { aircraftProjectile_t* projectile; if (ccs.numProjectiles >= MAX_PROJECTILESONGEOSCAPE) { Com_DPrintf(DEBUG_CLIENT, "Too many projectiles on map\n"); return false; } projectile = &ccs.projectiles[ccs.numProjectiles]; if (!weaponSlot->ammo) { Com_Printf("AIRFIGHT_AddProjectile: Error - no ammo assigned\n"); return false; } assert(weaponSlot->item); projectile->aircraftItem = weaponSlot->ammo; if (attackingBase) { projectile->attackingAircraft = nullptr; VectorSet(projectile->pos[0], attackingBase->pos[0], attackingBase->pos[1], 0); VectorSet(projectile->attackerPos, attackingBase->pos[0], attackingBase->pos[1], 0); } else if (attackingInstallation) { projectile->attackingAircraft = nullptr; VectorSet(projectile->pos[0], attackingInstallation->pos[0], attackingInstallation->pos[1], 0); VectorSet(projectile->attackerPos, attackingInstallation->pos[0], attackingInstallation->pos[1], 0); } else { assert(attacker); projectile->attackingAircraft = attacker; VectorSet(projectile->pos[0], attacker->pos[0], attacker->pos[1], 0); /* attacker may move, use attackingAircraft->pos */ VectorSet(projectile->attackerPos, 0, 0, 0); } projectile->numProjectiles++; assert(target); projectile->aimedAircraft = target; VectorSet(projectile->idleTarget, 0, 0, 0); projectile->time = 0; projectile->angle = 0.0f; projectile->bullets = weaponSlot->item->craftitem.bullets; projectile->beam = weaponSlot->item->craftitem.beam; projectile->rocket = !projectile->bullets && !projectile->beam; weaponSlot->ammoLeft--; if (weaponSlot->ammoLeft <= 0) AII_ReloadWeapon(weaponSlot); ccs.numProjectiles++; const char* sound; if (projectile->bullets) { sound = "geoscape/combat-gun"; } else if (projectile->beam) { sound = "geoscape/combat-airlaser"; } else if (projectile->rocket) { sound = "geoscape/combat-rocket"; } else { sound = nullptr; } if (sound != nullptr) cgi->S_StartLocalSample(sound, 1.0f); return true; }