void CInterceptHandler::AddShieldInterceptableProjectile(CWeaponProjectile* p) { for (std::list<CPlasmaRepulser*>::iterator wi = repulsors.begin(); wi != repulsors.end(); ++wi) { CPlasmaRepulser* shield = *wi; if (shield->weaponDef->shieldInterceptType & p->weaponDef->interceptedByShieldType) { shield->NewProjectile(p); } } }
float CInterceptHandler::AddShieldInterceptableBeam(CWeapon* emitter, const float3& start, const float3& dir, float length, float3& newDir, CPlasmaRepulser*& repulsedBy) { float minRange = 99999999; float3 tempDir; for (std::list<CPlasmaRepulser*>::iterator wi = plasmaRepulsors.begin(); wi != plasmaRepulsors.end(); ++wi) { CPlasmaRepulser* shield = *wi; if(shield->weaponDef->shieldInterceptType & emitter->weaponDef->interceptedByShieldType){ float dist = shield->NewBeam(emitter, start, dir, length, tempDir); if ((dist > 0) && (dist < minRange)) { minRange = dist; newDir = tempDir; repulsedBy = shield; } } } return minRange; }
float CInterceptHandler::AddShieldInterceptableBeam(CWeapon* emitter, const float3& start, const float3& dir, float length, float3& newDir, CPlasmaRepulser*& repulsedBy) { float minRange = std::numeric_limits<float>::max(); float3 tempDir; for (std::list<CPlasmaRepulser*>::iterator wi = repulsors.begin(); wi != repulsors.end(); ++wi) { CPlasmaRepulser* shield = *wi; if ((shield->weaponDef->shieldInterceptType & emitter->weaponDef->interceptedByShieldType) == 0) continue; const float dist = shield->NewBeam(emitter, start, dir, length, tempDir); if (dist <= 0.0f) continue; if (dist >= minRange) continue; minRange = dist; newDir = tempDir; repulsedBy = shield; } return minRange; }
void CLightningCannon::Fire(void) { float3 dir=targetPos-weaponMuzzlePos; dir.Normalize(); dir+=(gs->randVector()*sprayAngle+salvoError)*(1-owner->limExperience*0.5f); dir.Normalize(); CUnit* u=0; float r=helper->TraceRay(weaponMuzzlePos,dir,range,0,owner,u,collisionFlags); float3 newDir; CPlasmaRepulser* shieldHit; float shieldLength=interceptHandler.AddShieldInterceptableBeam(this,weaponMuzzlePos,dir,range,newDir,shieldHit); if(shieldLength<r){ r=shieldLength; if(shieldHit) { shieldHit->BeamIntercepted(this); } } // if(u) // u->DoDamage(damages,owner,ZeroVector); // Dynamic Damage DamageArray dynDamages; if (weaponDef->dynDamageExp > 0) dynDamages = weaponDefHandler->DynamicDamages(weaponDef->damages, weaponMuzzlePos, targetPos, weaponDef->dynDamageRange>0?weaponDef->dynDamageRange:weaponDef->range, weaponDef->dynDamageExp, weaponDef->dynDamageMin, weaponDef->dynDamageInverted); helper->Explosion(weaponMuzzlePos+dir*r,weaponDef->dynDamageExp>0?dynDamages:weaponDef->damages,areaOfEffect,weaponDef->edgeEffectiveness,weaponDef->explosionSpeed,owner,false,0.5f,true,false,weaponDef->explosionGenerator, u,dir, weaponDef->id); SAFE_NEW CLightningProjectile(weaponMuzzlePos, weaponMuzzlePos + dir * (r + 10), owner, color, weaponDef, 10, this); if (fireSoundId && (!weaponDef->soundTrigger || salvoLeft == salvoSize - 1)) sound->PlaySample(fireSoundId, owner, fireSoundVolume); }
void CLightningCannon::FireImpl() { float3 dir = targetPos - weaponMuzzlePos; dir.ANormalize(); dir += (gs->randVector() * sprayAngle + salvoError) * (1.0f - owner->limExperience * 0.5f); dir.ANormalize(); CUnit* u = 0; float r = helper->TraceRay(weaponMuzzlePos, dir, range, 0, owner, u, collisionFlags); float3 newDir; CPlasmaRepulser* shieldHit = 0; const float shieldLength = interceptHandler.AddShieldInterceptableBeam(this, weaponMuzzlePos, dir, range, newDir, shieldHit); if (shieldLength < r) { r = shieldLength; if (shieldHit) { shieldHit->BeamIntercepted(this); } } if (u) { if (u->unitDef->usePieceCollisionVolumes) { u->SetLastAttackedPiece(u->localmodel->pieces[0], gs->frameNum); } } // Dynamic Damage DamageArray dynDamages; if (weaponDef->dynDamageExp > 0) { dynDamages = weaponDefHandler->DynamicDamages( weaponDef->damages, weaponMuzzlePos, targetPos, weaponDef->dynDamageRange > 0? weaponDef->dynDamageRange: weaponDef->range, weaponDef->dynDamageExp, weaponDef->dynDamageMin, weaponDef->dynDamageInverted ); } helper->Explosion( weaponMuzzlePos + dir * r, weaponDef->dynDamageExp > 0? dynDamages: weaponDef->damages, areaOfEffect, weaponDef->edgeEffectiveness, weaponDef->explosionSpeed, owner, false, 0.5f, true, false, weaponDef->explosionGenerator, u, dir, weaponDef->id ); new CLightningProjectile( weaponMuzzlePos, weaponMuzzlePos + dir * (r + 10), owner, color, weaponDef, 10, this ); }
void CLightningCannon::FireImpl() { float3 dir(targetPos - weaponMuzzlePos); dir.Normalize(); dir += (gs->randVector() * sprayAngle + salvoError) * (1.0f - owner->limExperience * weaponDef->ownerExpAccWeight); dir.Normalize(); CUnit* u = NULL; CFeature* f = NULL; float r = TraceRay::TraceRay(weaponMuzzlePos, dir, range, collisionFlags, owner, u, f); float3 newDir; CPlasmaRepulser* shieldHit = NULL; const float shieldLength = interceptHandler.AddShieldInterceptableBeam(this, weaponMuzzlePos, dir, range, newDir, shieldHit); if (shieldLength < r) { r = shieldLength; if (shieldHit) { shieldHit->BeamIntercepted(this); } } if (u) { if (u->unitDef->usePieceCollisionVolumes) { u->SetLastAttackedPiece(u->localmodel->GetRoot(), gs->frameNum); } } // Dynamic Damage DamageArray damageArray; if (weaponDef->dynDamageExp > 0) { damageArray = weaponDefHandler->DynamicDamages( weaponDef->damages, weaponMuzzlePos, targetPos, weaponDef->dynDamageRange > 0? weaponDef->dynDamageRange: weaponDef->range, weaponDef->dynDamageExp, weaponDef->dynDamageMin, weaponDef->dynDamageInverted ); } else { damageArray = weaponDef->damages; } CGameHelper::ExplosionParams params = { weaponMuzzlePos + dir * r, dir, damageArray, weaponDef, owner, u, // hitUnit f, // hitFeature areaOfEffect, weaponDef->edgeEffectiveness, weaponDef->explosionSpeed, 0.5f, // gfxMod weaponDef->impactOnly, weaponDef->noExplode || weaponDef->noSelfDamage, // ignoreOwner false // damageGround }; helper->Explosion(params); new CLightningProjectile( weaponMuzzlePos, weaponMuzzlePos + dir * (r + 10), owner, color, weaponDef, 10, this ); }
void CUnitScript::SetUnitVal(int val, int param) { // may happen in case one uses Spring.SetUnitCOBValue (Lua) on a unit with CNullUnitScript if (!unit) { ShowUnitScriptError("Error: no unit (in SetUnitVal)"); return; } #ifndef _CONSOLE switch (val) { case ACTIVATION: { if(unit->unitDef->onoffable) { Command c(CMD_ONOFF, 0, (param == 0) ? 0 : 1); unit->commandAI->GiveCommand(c); } else { if(param == 0) { unit->Deactivate(); } else { unit->Activate(); } } break; } case STANDINGMOVEORDERS: { if (param >= 0 && param <= 2) { Command c(CMD_MOVE_STATE, 0, param); unit->commandAI->GiveCommand(c); } break; } case STANDINGFIREORDERS: { if (param >= 0 && param <= 2) { Command c(CMD_FIRE_STATE, 0, param); unit->commandAI->GiveCommand(c); } break; } case HEALTH: { break; } case INBUILDSTANCE: { unit->inBuildStance = (param != 0); break; } case BUSY: { busy = (param != 0); break; } case PIECE_XZ: { break; } case PIECE_Y: { break; } case UNIT_XZ: { break; } case UNIT_Y: { break; } case UNIT_HEIGHT: { break; } case XZ_ATAN: { break; } case XZ_HYPOT: { break; } case ATAN: { break; } case HYPOT: { break; } case GROUND_HEIGHT: { break; } case GROUND_WATER_HEIGHT: { break; } case BUILD_PERCENT_LEFT: { break; } case YARD_OPEN: { if (unit->blockMap != NULL) { // note: if this unit is a factory, engine-controlled // OpenYard() and CloseYard() calls can interfere with // the yardOpen state (they probably should be removed // at some point) if (param == 0) { if (groundBlockingObjectMap->CanCloseYard(unit)) { groundBlockingObjectMap->CloseBlockingYard(unit); } } else { if (groundBlockingObjectMap->CanOpenYard(unit)) { groundBlockingObjectMap->OpenBlockingYard(unit); } } } break; } case BUGGER_OFF: { if (param != 0) { CGameHelper::BuggerOff(unit->pos + unit->frontdir * unit->radius, unit->radius * 1.5f, true, false, unit->team, NULL); } break; } case ARMORED: { if (param) { unit->curArmorMultiple = unit->armoredMultiple; } else { unit->curArmorMultiple = 1; } unit->armoredState = (param != 0); break; } case VETERAN_LEVEL: { unit->experience = param * 0.01f; break; } case MAX_SPEED: { // interpret negative values as non-persistent changes unit->commandAI->SetScriptMaxSpeed(std::max(param, -param) / float(COBSCALE), (param >= 0)); break; } case CLOAKED: { unit->wantCloak = !!param; break; } case WANT_CLOAK: { unit->wantCloak = !!param; break; } case UPRIGHT: { unit->upright = !!param; break; } case HEADING: { unit->heading = param % COBSCALE; unit->UpdateDirVectors(!unit->upright); unit->UpdateMidAndAimPos(); } break; case LOS_RADIUS: { unit->ChangeLos(param, unit->realAirLosRadius); unit->realLosRadius = param; break; } case AIR_LOS_RADIUS: { unit->ChangeLos(unit->realLosRadius, param); unit->realAirLosRadius = param; break; } case RADAR_RADIUS: { unit->ChangeSensorRadius(&unit->radarRadius, param); break; } case JAMMER_RADIUS: { unit->ChangeSensorRadius(&unit->jammerRadius, param); break; } case SONAR_RADIUS: { unit->ChangeSensorRadius(&unit->sonarRadius, param); break; } case SONAR_JAM_RADIUS: { unit->ChangeSensorRadius(&unit->sonarJamRadius, param); break; } case SEISMIC_RADIUS: { unit->ChangeSensorRadius(&unit->seismicRadius, param); break; } case CURRENT_FUEL: { unit->currentFuel = param / (float) COBSCALE; break; } case SHIELD_POWER: { if (unit->shieldWeapon != NULL) { CPlasmaRepulser* shield = static_cast<CPlasmaRepulser*>(unit->shieldWeapon); shield->SetCurPower(std::max(0.0f, float(param) / float(COBSCALE))); } break; } case STEALTH: { unit->stealth = !!param; break; } case SONAR_STEALTH: { unit->sonarStealth = !!param; break; } case CRASHING: { AAirMoveType* amt = dynamic_cast<AAirMoveType*>(unit->moveType); if (amt != NULL) { if (!!param) { amt->SetState(AAirMoveType::AIRCRAFT_CRASHING); } else { amt->SetState(AAirMoveType::AIRCRAFT_FLYING); } } break; } case CHANGE_TARGET: { if (param < 0) { return; } if (param >= unit->weapons.size()) { return; } unit->weapons[param]->avoidTarget = true; break; } case CEG_DAMAGE: { unit->cegDamage = param; break; } case FLANK_B_MODE: unit->flankingBonusMode = param; break; case FLANK_B_MOBILITY_ADD: unit->flankingBonusMobilityAdd = (param / (float)COBSCALE); break; case FLANK_B_MAX_DAMAGE: { float mindamage = unit->flankingBonusAvgDamage - unit->flankingBonusDifDamage; unit->flankingBonusAvgDamage = (param / (float)COBSCALE + mindamage)*0.5f; unit->flankingBonusDifDamage = (param / (float)COBSCALE - mindamage)*0.5f; break; } case FLANK_B_MIN_DAMAGE: { float maxdamage = unit->flankingBonusAvgDamage + unit->flankingBonusDifDamage; unit->flankingBonusAvgDamage = (maxdamage + param / (float)COBSCALE)*0.5f; unit->flankingBonusDifDamage = (maxdamage - param / (float)COBSCALE)*0.5f; break; } default: { if ((val >= GLOBAL_VAR_START) && (val <= GLOBAL_VAR_END)) { globalVars[val - GLOBAL_VAR_START] = param; } else if ((val >= TEAM_VAR_START) && (val <= TEAM_VAR_END)) { teamVars[unit->team][val - TEAM_VAR_START] = param; } else if ((val >= ALLY_VAR_START) && (val <= ALLY_VAR_END)) { allyVars[unit->allyteam][val - ALLY_VAR_START] = param; } else if ((val >= UNIT_VAR_START) && (val <= UNIT_VAR_END)) { unitVars[val - UNIT_VAR_START] = param; } else { LOG_L(L_ERROR, "CobError: Unknown set constant %d", val); } } } #endif }
void CLightningCannon::FireImpl() { float3 dir(targetPos - weaponMuzzlePos); dir.Normalize(); dir += (gs->randVector() * sprayAngle + salvoError) * (1.0f - owner->limExperience * weaponDef->ownerExpAccWeight); dir.Normalize(); CUnit* u = NULL; CFeature* f = NULL; float r = 0.0f; { const CUnit* cu = NULL; const CFeature* cf = NULL; r = helper->TraceRay(weaponMuzzlePos, dir, range, 0, (const CUnit*)owner, cu, collisionFlags, &cf); u = const_cast<CUnit*>(cu); f = const_cast<CFeature*>(cf); } float3 newDir; CPlasmaRepulser* shieldHit = NULL; const float shieldLength = interceptHandler.AddShieldInterceptableBeam(this, weaponMuzzlePos, dir, range, newDir, shieldHit); if (shieldLength < r) { r = shieldLength; if (shieldHit) { shieldHit->BeamIntercepted(this); } } if (u) { if (u->unitDef->usePieceCollisionVolumes) { u->SetLastAttackedPiece(u->localmodel->GetRoot(), gs->frameNum); } } // Dynamic Damage DamageArray dynDamages; if (weaponDef->dynDamageExp > 0) { dynDamages = weaponDefHandler->DynamicDamages( weaponDef->damages, weaponMuzzlePos, targetPos, weaponDef->dynDamageRange > 0? weaponDef->dynDamageRange: weaponDef->range, weaponDef->dynDamageExp, weaponDef->dynDamageMin, weaponDef->dynDamageInverted ); } helper->Explosion( weaponMuzzlePos + dir * r, weaponDef->dynDamageExp > 0? dynDamages: weaponDef->damages, areaOfEffect, weaponDef->edgeEffectiveness, weaponDef->explosionSpeed, owner, false, 0.5f, weaponDef->noExplode || weaponDef->noSelfDamage, /*true*/ weaponDef->impactOnly, /*false*/ weaponDef->explosionGenerator, u, dir, weaponDef->id, f ); new CLightningProjectile( weaponMuzzlePos, weaponMuzzlePos + dir * (r + 10), owner, color, weaponDef, 10, this ); }
void CBeamLaser::FireInternal(float3 dir, bool sweepFire) { float rangeMod=1.3f; #ifdef DIRECT_CONTROL_ALLOWED if(owner->directControl) rangeMod=0.95f; #endif float maxLength=range*rangeMod; float curLength=0; float3 curPos=weaponPos; float3 hitPos; bool tryAgain=true; CUnit* hit; // increase range if targets are searched for in a cylinder if (cylinderTargetting > 0.01) { //const float3 up(0, owner->radius*cylinderTargetting, 0); //const float uplen = up.dot(dir); const float uplen = owner->radius*cylinderTargetting * dir.y; maxLength = sqrt(maxLength*maxLength + uplen*uplen); } // increase range if targetting edge of hitsphere if (targetType == Target_Unit && targetUnit && targetBorder != 0) { maxLength += targetUnit->radius*targetBorder; } for(int tries=0;tries<5 && tryAgain;++tries){ tryAgain=false; hit=0; float length=helper->TraceRay(curPos,dir,maxLength-curLength,damages[0],owner,hit); if(hit && hit->allyteam == owner->allyteam && sweepFire){ //never damage friendlies with sweepfire lastFireFrame = 0; return; } float3 newDir; CPlasmaRepulser* shieldHit; float shieldLength=interceptHandler.AddShieldInterceptableBeam(this,curPos,dir,length,newDir,shieldHit); if(shieldLength<length){ length=shieldLength; bool repulsed=shieldHit->BeamIntercepted(this); if(repulsed){ tryAgain=true; } } hitPos=curPos+dir*length; float baseAlpha=weaponDef->intensity*255; float startAlpha=(1-curLength/(range*1.3f))*baseAlpha; float endAlpha=(1-(curLength+length)/(range*1.3f))*baseAlpha; if(weaponDef->largeBeamLaser) SAFE_NEW CLargeBeamLaserProjectile(curPos, hitPos, color, weaponDef->visuals.color2, owner,weaponDef); else SAFE_NEW CBeamLaserProjectile(curPos,hitPos,startAlpha,endAlpha,color,weaponDef->visuals.color2, owner,weaponDef->thickness,weaponDef->corethickness, weaponDef->laserflaresize, weaponDef); curPos=hitPos; curLength+=length; dir=newDir; } // fix negative damage when hitting big spheres float actualRange = range; if (hit && targetBorder > 0) { actualRange += hit->radius*targetBorder; } // make it possible to always hit with some minimal intensity (melee weapons have use for that) float intensity=max(minIntensity, 1-(curLength)/(actualRange*2)); if(curLength<maxLength) { // Dynamic Damage DamageArray dynDamages; if (weaponDef->dynDamageExp > 0) dynDamages = weaponDefHandler->DynamicDamages(weaponDef->damages, weaponPos, curPos, weaponDef->dynDamageRange>0?weaponDef->dynDamageRange:weaponDef->range, weaponDef->dynDamageExp, weaponDef->dynDamageMin, weaponDef->dynDamageInverted); helper->Explosion(hitPos, weaponDef->dynDamageExp>0?dynDamages*(intensity*damageMul):weaponDef->damages*(intensity*damageMul), areaOfEffect, weaponDef->edgeEffectiveness, weaponDef->explosionSpeed,owner, true, 1.0f, false, weaponDef->explosionGenerator, hit, dir, weaponDef->id); } if(targetUnit) lastFireFrame = gs->frameNum; }
void CBeamLaser::FireInternal(float3 dir, bool sweepFire) { // fix negative damage when hitting big spheres float actualRange = range; float rangeMod = 1.0f; if (dynamic_cast<CBuilding*>(owner) == NULL) { // help units fire while chasing rangeMod = 1.3f; } if (owner->fpsControlPlayer != NULL) { rangeMod = 0.95f; } float maxLength = range * rangeMod; float curLength = 0.0f; float3 curPos = weaponMuzzlePos; float3 hitPos; dir += ((gs->randVector() * sprayAngle * (1.0f - owner->limExperience * weaponDef->ownerExpAccWeight))); dir.SafeNormalize(); bool tryAgain = true; // increase range if targets are searched for in a cylinder if (cylinderTargetting > 0.01f) { const float verticalDist = owner->radius * cylinderTargetting * dir.y; const float maxLengthModSq = maxLength * maxLength + verticalDist * verticalDist; maxLength = math::sqrt(maxLengthModSq); } // increase range if targetting edge of hitsphere if (targetType == Target_Unit && targetUnit && targetBorder != 0) { maxLength += (targetUnit->radius * targetBorder); } // unit at the end of the beam CUnit* hitUnit = NULL; CFeature* hitFeature = NULL; CPlasmaRepulser* hitShield = NULL; for (int tries = 0; tries < 5 && tryAgain; ++tries) { tryAgain = false; float length = TraceRay::TraceRay(curPos, dir, maxLength - curLength, collisionFlags, owner, hitUnit, hitFeature); if (hitUnit && teamHandler->AlliedTeams(hitUnit->team, owner->team) && sweepFire) { // never damage friendlies with sweepfire lastFireFrame = 0; return; } float3 newDir; const float shieldLength = interceptHandler.AddShieldInterceptableBeam(this, curPos, dir, length, newDir, hitShield); if (shieldLength < length) { length = shieldLength; tryAgain = hitShield->BeamIntercepted(this, damageMul); // repulsed } hitPos = curPos + dir * length; const float baseAlpha = weaponDef->intensity * 255.0f; const float startAlpha = (1.0f - (curLength ) / (range * 1.3f)) * baseAlpha; const float endAlpha = (1.0f - (curLength + length) / (range * 1.3f)) * baseAlpha; if (weaponDef->largeBeamLaser) { new CLargeBeamLaserProjectile(curPos, hitPos, color, weaponDef->visuals.color2, owner, weaponDef); } else { new CBeamLaserProjectile(curPos, hitPos, startAlpha, endAlpha, color, owner, weaponDef); } curPos = hitPos; curLength += length; dir = newDir; } if (hitUnit) { if (hitUnit->unitDef->usePieceCollisionVolumes) { // getting the actual piece here is probably overdoing it // TODO change this if we really need propper flanking bonus support // for beam-lasers hitUnit->SetLastAttackedPiece(hitUnit->localmodel->GetRoot(), gs->frameNum); } if (targetBorder > 0) { actualRange += hitUnit->radius * targetBorder; } } // make it possible to always hit with some minimal intensity (melee weapons have use for that) const float hitIntensity = std::max(minIntensity, 1.0f - (curLength) / (actualRange * 2)); if (curLength < maxLength) { // Dynamic Damage DamageArray dynDamages; if (weaponDef->dynDamageExp > 0) { dynDamages = weaponDefHandler->DynamicDamages( weaponDef->damages, weaponMuzzlePos, curPos, weaponDef->dynDamageRange > 0? weaponDef->dynDamageRange: weaponDef->range, weaponDef->dynDamageExp, weaponDef->dynDamageMin, weaponDef->dynDamageInverted ); } DamageArray damageArray = weaponDef->dynDamageExp > 0? dynDamages * (hitIntensity * damageMul): weaponDef->damages * (hitIntensity * damageMul); CGameHelper::ExplosionParams params = { hitPos, dir, damageArray, weaponDef, owner, hitUnit, hitFeature, areaOfEffect, weaponDef->edgeEffectiveness, weaponDef->explosionSpeed, 1.0f, // gfxMod weaponDef->impactOnly, weaponDef->noExplode || weaponDef->noSelfDamage, // ignoreOwner true // damageGround }; helper->Explosion(params); } if (targetUnit) { lastFireFrame = gs->frameNum; } }
void CBeamLaser::FireInternal(float3 dir, bool sweepFire) { float rangeMod = 1.0f; if (dynamic_cast<CBuilding*>(owner) == NULL) { // help units fire while chasing rangeMod = 1.3f; } if (owner->directControl) { rangeMod = 0.95f; } float maxLength = range * rangeMod; float curLength = 0.0f; float3 curPos = weaponMuzzlePos; float3 hitPos; dir += gs->randVector() * sprayAngle * (1 - owner->limExperience * 0.7f); dir.ANormalize(); bool tryAgain = true; // unit at the end of the beam CUnit* hit = 0; // increase range if targets are searched for in a cylinder if (cylinderTargetting > 0.01f) { // const float3 up(0, owner->radius*cylinderTargetting, 0); // const float uplen = up.dot(dir); const float uplen = owner->radius * cylinderTargetting * dir.y; maxLength = streflop::sqrtf(maxLength * maxLength + uplen * uplen); } // increase range if targetting edge of hitsphere if (targetType == Target_Unit && targetUnit && targetBorder != 0) { maxLength += targetUnit->radius * targetBorder; } for (int tries = 0; tries < 5 && tryAgain; ++tries) { tryAgain = false; hit = 0; float length = helper->TraceRay( curPos, dir, maxLength - curLength, weaponDef->damages[0], owner, hit, collisionFlags ); if (hit && hit->allyteam == owner->allyteam && sweepFire) { // never damage friendlies with sweepfire lastFireFrame = 0; return; } float3 newDir; CPlasmaRepulser* shieldHit = 0; const float shieldLength = interceptHandler.AddShieldInterceptableBeam(this, curPos, dir, length, newDir, shieldHit); if (shieldLength < length) { length = shieldLength; if (shieldHit->BeamIntercepted(this, damageMul)) { // repulsed tryAgain = true; } } hitPos = curPos + dir * length; const float baseAlpha = weaponDef->intensity * 255.0f; const float startAlpha = (1.0f - (curLength ) / (range * 1.3f)) * baseAlpha; const float endAlpha = (1.0f - (curLength + length) / (range * 1.3f)) * baseAlpha; if (weaponDef->largeBeamLaser) { new CLargeBeamLaserProjectile(curPos, hitPos, color, weaponDef->visuals.color2, owner, weaponDef); } else { new CBeamLaserProjectile( curPos, hitPos, startAlpha, endAlpha, color, weaponDef->visuals.color2, owner, weaponDef->thickness, weaponDef->corethickness, weaponDef->laserflaresize, weaponDef, weaponDef->visuals.beamttl, weaponDef->visuals.beamdecay ); } curPos = hitPos; curLength += length; dir = newDir; } // fix negative damage when hitting big spheres float actualRange = range; if (hit) { if (hit->unitDef->usePieceCollisionVolumes) { // getting the actual piece here is probably overdoing it hit->SetLastAttackedPiece(hit->localmodel->pieces[0], gs->frameNum); } if (targetBorder > 0) { actualRange += hit->radius * targetBorder; } } // make it possible to always hit with some minimal intensity (melee weapons have use for that) const float intensity = std::max(minIntensity, 1.0f - (curLength) / (actualRange * 2)); if (curLength < maxLength) { // Dynamic Damage DamageArray dynDamages; if (weaponDef->dynDamageExp > 0) { dynDamages = weaponDefHandler->DynamicDamages( weaponDef->damages, weaponMuzzlePos, curPos, weaponDef->dynDamageRange > 0? weaponDef->dynDamageRange: weaponDef->range, weaponDef->dynDamageExp, weaponDef->dynDamageMin, weaponDef->dynDamageInverted ); } helper->Explosion( hitPos, weaponDef->dynDamageExp > 0? dynDamages * (intensity * damageMul): weaponDef->damages * (intensity * damageMul), areaOfEffect, weaponDef->edgeEffectiveness, weaponDef->explosionSpeed, owner, true, 1.0f, weaponDef->noExplode || weaponDef->noSelfDamage, /*false*/ weaponDef->impactOnly, /*false*/ weaponDef->explosionGenerator, hit, dir, weaponDef->id ); } if (targetUnit) { lastFireFrame = gs->frameNum; } }
void CBeamLaser::FireInternal(float3 curDir) { float actualRange = range; float rangeMod = 1.0f; if (!owner->unitDef->IsImmobileUnit()) { // help units fire while chasing rangeMod = 1.3f; } if (owner->UnderFirstPersonControl()) { rangeMod = 0.95f; } bool tryAgain = true; bool doDamage = true; float maxLength = range * rangeMod; float curLength = 0.0f; float3 curPos = weaponMuzzlePos; float3 hitPos; float3 newDir; // objects at the end of the beam CUnit* hitUnit = NULL; CFeature* hitFeature = NULL; CPlasmaRepulser* hitShield = NULL; CollisionQuery hitColQuery; if (!sweepFireState.IsSweepFiring()) { curDir += (gs->randVector() * SprayAngleExperience()); curDir.SafeNormalize(); // increase range if targets are searched for in a cylinder if (cylinderTargeting > 0.01f) { const float verticalDist = owner->radius * cylinderTargeting * curDir.y; const float maxLengthModSq = maxLength * maxLength + verticalDist * verticalDist; maxLength = math::sqrt(maxLengthModSq); } // adjust range if targetting edge of hitsphere if (targetType == Target_Unit && targetUnit != NULL && targetBorder != 0.0f) { maxLength += (targetUnit->radius * targetBorder); } } else { // restrict the range when sweeping maxLength = std::min(maxLength, sweepFireState.GetTargetDist3D() * 1.125f); } for (int tries = 0; tries < 5 && tryAgain; ++tries) { float beamLength = TraceRay::TraceRay(curPos, curDir, maxLength - curLength, collisionFlags, owner, hitUnit, hitFeature, &hitColQuery); if (hitUnit != NULL && teamHandler->AlliedTeams(hitUnit->team, owner->team)) { if (sweepFireState.IsSweepFiring() && !sweepFireState.DamageAllies()) { doDamage = false; break; } } if (!weaponDef->waterweapon) { // terminate beam at water surface if necessary if ((curDir.y < 0.0f) && ((curPos.y + curDir.y * beamLength) <= 0.0f)) { beamLength = curPos.y / -curDir.y; } } // if the beam gets intercepted, this modifies newDir // // we do more than one trace-iteration and set dir to // newDir only in the case there is a shield in our way const float shieldLength = interceptHandler.AddShieldInterceptableBeam(this, curPos, curDir, beamLength, newDir, hitShield); if (shieldLength < beamLength) { beamLength = shieldLength; tryAgain = hitShield->BeamIntercepted(this, salvoDamageMult); } else { tryAgain = false; } // same as hitColQuery.GetHitPos() if no water or shield in way hitPos = curPos + curDir * beamLength; { const float baseAlpha = weaponDef->intensity * 255.0f; const float startAlpha = (1.0f - (curLength ) / maxLength); const float endAlpha = (1.0f - (curLength + beamLength) / maxLength); ProjectileParams pparams = GetProjectileParams(); pparams.pos = curPos; pparams.end = hitPos; pparams.ttl = weaponDef->beamLaserTTL; pparams.startAlpha = Clamp(startAlpha * baseAlpha, 0.0f, 255.0f); pparams.endAlpha = Clamp(endAlpha * baseAlpha, 0.0f, 255.0f); WeaponProjectileFactory::LoadProjectile(pparams); } curPos = hitPos; curDir = newDir; curLength += beamLength; } if (!doDamage) return; if (hitUnit != NULL) { hitUnit->SetLastAttackedPiece(hitColQuery.GetHitPiece(), gs->frameNum); if (targetBorder > 0.0f) { actualRange += (hitUnit->radius * targetBorder); } } if (curLength < maxLength) { const DamageArray& baseDamages = (weaponDef->dynDamageExp <= 0.0f)? weaponDef->damages: weaponDefHandler->DynamicDamages( weaponDef->damages, weaponMuzzlePos, curPos, (weaponDef->dynDamageRange > 0.0f)? weaponDef->dynDamageRange: weaponDef->range, weaponDef->dynDamageExp, weaponDef->dynDamageMin, weaponDef->dynDamageInverted ); // make it possible to always hit with some minimal intensity (melee weapons have use for that) const float hitIntensity = std::max(minIntensity, 1.0f - curLength / (actualRange * 2.0f)); const DamageArray damages = baseDamages * (hitIntensity * salvoDamageMult); const CGameHelper::ExplosionParams params = { hitPos, curDir, damages, weaponDef, owner, hitUnit, hitFeature, craterAreaOfEffect, damageAreaOfEffect, weaponDef->edgeEffectiveness, weaponDef->explosionSpeed, 1.0f, // gfxMod weaponDef->impactOnly, weaponDef->noExplode || weaponDef->noSelfDamage, // ignoreOwner true, // damageGround -1u // projectileID }; helper->Explosion(params); } }
void CLightningCannon::FireImpl(bool scriptCall) { float3 curPos = weaponMuzzlePos; float3 curDir = (targetPos - curPos).Normalize(); float3 newDir = curDir; curDir += (gs->randVector() * SprayAngleExperience() + SalvoErrorExperience()); curDir.Normalize(); CUnit* hitUnit = NULL; CFeature* hitFeature = NULL; CPlasmaRepulser* hitShield = NULL; CollisionQuery hitColQuery; float boltLength = TraceRay::TraceRay(curPos, curDir, range, collisionFlags, owner, hitUnit, hitFeature, &hitColQuery); if (!weaponDef->waterweapon) { // terminate bolt at water surface if necessary if ((curDir.y < 0.0f) && ((curPos.y + curDir.y * boltLength) <= 0.0f)) { boltLength = curPos.y / -curDir.y; } } const float shieldLength = interceptHandler.AddShieldInterceptableBeam(this, curPos, curDir, range, newDir, hitShield); if (shieldLength < boltLength) { boltLength = shieldLength; hitShield->BeamIntercepted(this); } if (hitUnit != NULL) { hitUnit->SetLastAttackedPiece(hitColQuery.GetHitPiece(), gs->frameNum); } const DamageArray& damageArray = (weaponDef->dynDamageExp <= 0.0f)? weaponDef->damages: weaponDefHandler->DynamicDamages( weaponDef->damages, weaponMuzzlePos, targetPos, (weaponDef->dynDamageRange > 0.0f)? weaponDef->dynDamageRange: weaponDef->range, weaponDef->dynDamageExp, weaponDef->dynDamageMin, weaponDef->dynDamageInverted ); const CGameHelper::ExplosionParams params = { curPos + curDir * boltLength, // hitPos (same as hitColQuery.GetHitPos() if no water or shield in way) curDir, damageArray, weaponDef, owner, hitUnit, hitFeature, craterAreaOfEffect, damageAreaOfEffect, weaponDef->edgeEffectiveness, weaponDef->explosionSpeed, 0.5f, // gfxMod weaponDef->impactOnly, weaponDef->noExplode || weaponDef->noSelfDamage, // ignoreOwner false, // damageGround -1u // projectileID }; helper->Explosion(params); ProjectileParams pparams = GetProjectileParams(); pparams.pos = curPos; pparams.end = curPos + curDir * (boltLength + 10.0f); pparams.ttl = 10; WeaponProjectileFactory::LoadProjectile(pparams); }
void CLightningCannon::FireImpl() { float3 curPos = weaponMuzzlePos; float3 hitPos; float3 curDir = (targetPos - curPos).Normalize(); float3 newDir = curDir; curDir += (gs->randVector() * sprayAngle + salvoError) * (1.0f - owner->limExperience * weaponDef->ownerExpAccWeight); curDir.Normalize(); CUnit* hitUnit = NULL; CFeature* hitFeature = NULL; CPlasmaRepulser* hitShield = NULL; float boltLength = TraceRay::TraceRay(curPos, curDir, range, collisionFlags, owner, hitUnit, hitFeature); if (!weaponDef->waterweapon) { // terminate bolt at water surface if necessary if ((curDir.y < 0.0f) && ((curPos.y + curDir.y * boltLength) <= 0.0f)) { boltLength = curPos.y / -curDir.y; } } const float shieldLength = interceptHandler.AddShieldInterceptableBeam(this, curPos, curDir, range, newDir, hitShield); if (shieldLength < boltLength) { boltLength = shieldLength; hitShield->BeamIntercepted(this); } hitPos = curPos + curDir * boltLength; if (hitUnit != NULL) { hitUnit->SetLastAttackedPiece(hitUnit->localModel->GetRoot(), gs->frameNum); } const DamageArray& damageArray = (weaponDef->dynDamageExp <= 0.0f)? weaponDef->damages: weaponDefHandler->DynamicDamages( weaponDef->damages, weaponMuzzlePos, targetPos, (weaponDef->dynDamageRange > 0.0f)? weaponDef->dynDamageRange: weaponDef->range, weaponDef->dynDamageExp, weaponDef->dynDamageMin, weaponDef->dynDamageInverted ); const CGameHelper::ExplosionParams params = { hitPos, curDir, damageArray, weaponDef, owner, hitUnit, hitFeature, craterAreaOfEffect, damageAreaOfEffect, weaponDef->edgeEffectiveness, weaponDef->explosionSpeed, 0.5f, // gfxMod weaponDef->impactOnly, weaponDef->noExplode || weaponDef->noSelfDamage, // ignoreOwner false // damageGround }; helper->Explosion(params); ProjectileParams pparams = GetProjectileParams(); pparams.pos = curPos; pparams.end = curPos + curDir * (boltLength + 10.0f); pparams.ttl = 10; new CLightningProjectile(pparams, color); }