void CHoverAirMoveType::UpdateAirPhysics() { float3& pos = owner->pos; float3& speed = owner->speed; if (!((gs->frameNum + owner->id) & 3)) { CheckForCollision(); } const float yspeed = speed.y; speed.y = 0.0f; const float3 delta = wantedSpeed - speed; const float deltaDotSpeed = (speed != ZeroVector)? delta.dot(speed): 1.0f; if (deltaDotSpeed == 0.0f) { // we have the wanted speed } else if (deltaDotSpeed > 0.0f) { // accelerate const float sqdl = delta.SqLength(); if (sqdl < Square(accRate)) { speed = wantedSpeed; } else { speed += delta / math::sqrt(sqdl) * accRate; } } else { // break const float sqdl = delta.SqLength(); if (sqdl < Square(decRate)) { speed = wantedSpeed; } else { speed += delta / math::sqrt(sqdl) * decRate; } } float minH = 0.0f; // minimum altitude at (pos.x, pos.z) float curH = 0.0f; // current altitude at (pos.x, pos.z) if (UseSmoothMesh()) { minH = owner->unitDef->canSubmerge? smoothGround->GetHeight(pos.x, pos.z): smoothGround->GetHeightAboveWater(pos.x, pos.z); } else { minH = owner->unitDef->canSubmerge? ground->GetHeightReal(pos.x, pos.z): ground->GetHeightAboveWater(pos.x, pos.z); } speed.y = yspeed; pos.y = std::max(pos.y, minH); curH = pos.y - minH; if (curH < 4.0f) { speed.x *= 0.95f; speed.z *= 0.95f; } float wh = wantedHeight; if (lastColWarningType == 2) { const float3 dir = lastColWarning->midPos - owner->midPos; const float3 sdir = lastColWarning->speed - speed; if (speed.dot(dir + sdir * 20.0f) < 0.0f) { if (lastColWarning->midPos.y > owner->pos.y) { wh -= 30.0f; } else { wh += 50.0f; } } } float ws = 0.0f; if (curH < wh) { ws = altitudeRate; if (speed.y > 0.0001f && (wh - curH) / speed.y * accRate * 1.5f < speed.y) { ws = 0.0f; } } else { ws = -altitudeRate; if (speed.y < -0.0001f && (wh - curH) / speed.y * accRate * 0.7f < -speed.y) { ws = 0.0f; } } if (fabs(wh - curH) > 2.0f) { if (speed.y > ws) { speed.y = std::max(ws, speed.y - accRate * 1.5f); } else if (!owner->beingBuilt) { // let them accelerate upward faster if close to ground speed.y = std::min(ws, speed.y + accRate * (curH < 20.0f? 2.0f: 0.7f)); } } else { speed.y = speed.y * 0.95; } if (modInfo.allowAirPlanesToLeaveMap || (pos + speed).CheckInBounds()) { pos += speed; } }
bool Plane::IsInPositiveDirection(const float3 &directionVector) const { assume(directionVector.IsNormalized()); return normal.Dot(directionVector) >= 0.f; }
Plane::Plane(const Line &line, const float3 &normal) { float3 perpNormal = normal - normal.ProjectToNorm(line.dir); Set(line.pos, perpNormal.Normalized()); }
void CPlasmaRepulser::Update(void) { const int defHitFrames = weaponDef->visibleShieldHitFrames; const bool couldBeVisible = (weaponDef->visibleShield || (defHitFrames > 0)); if (startShowingShield) { startShowingShield = false; if (couldBeVisible) { // 32 parts for (int y = 0; y < 16; y += 4) { for (int x = 0; x < 32; x += 4) { visibleShieldParts.push_back( SAFE_NEW CShieldPartProjectile(owner->pos, x, y, radius, weaponDef->shieldBadColor, weaponDef->shieldAlpha, weaponDef->visuals.texture1, owner) ); } } } } if (isEnabled && (curPower < weaponDef->shieldPower)) { if (owner->UseEnergy(weaponDef->shieldPowerRegenEnergy * (1.0f / 30.0f))) { curPower += weaponDef->shieldPowerRegen * (1.0f / 30.0f); } } weaponPos = owner->pos + (owner->frontdir * relWeaponPos.z) + (owner->updir * relWeaponPos.y) + (owner->rightdir * relWeaponPos.x); if (couldBeVisible) { float drawAlpha = 0.0f; const int oldFrames = hitFrames; if (hitFrames > 0) { drawAlpha += float(hitFrames) / float(defHitFrames); hitFrames--; } if ((isEnabled != wasEnabled) || (hitFrames != oldFrames) || (curPower != lastPower)) { if (weaponDef->visibleShield) { drawAlpha += 1.0f; } drawAlpha = min(1.0f, drawAlpha * weaponDef->shieldAlpha); const float colorMix = min(1.0f, curPower / max(1.0f, weaponDef->shieldPower)); const float3 color = (weaponDef->shieldGoodColor * colorMix) + (weaponDef->shieldBadColor * (1.0f - colorMix)); std::list<CShieldPartProjectile*>::iterator si; for (si = visibleShieldParts.begin(); si != visibleShieldParts.end(); ++si) { (*si)->centerPos = weaponPos; (*si)->color = color; if (isEnabled) { (*si)->baseAlpha = drawAlpha; } else { (*si)->baseAlpha = 0.0f; } } } } if (isEnabled) { for (std::list<CWeaponProjectile*>::iterator pi=incoming.begin();pi!=incoming.end();++pi) { const float3 dif = (*pi)->pos-owner->pos; if ((*pi)->checkCol && dif.SqLength()<sqRadius && curPower > (*pi)->weaponDef->damages[0]) { if (gs->Team(owner->team)->energy > weaponDef->shieldEnergyUse) { if (weaponDef->shieldRepulser) { // bounce the projectile const int type = (*pi)->ShieldRepulse(this, weaponPos, weaponDef->shieldForce, weaponDef->shieldMaxSpeed); if (type == 0) { continue; } else if (type == 1) { owner->UseEnergy(weaponDef->shieldEnergyUse); if (weaponDef->shieldPower != 0) { curPower -= (*pi)->weaponDef->damages[0]; } } else { owner->UseEnergy(weaponDef->shieldEnergyUse / 30.0f); if (weaponDef->shieldPower != 0) { curPower -= (*pi)->weaponDef->damages[0] / 30.0f; } } if (weaponDef->visibleShieldRepulse) { if (hasGfx.find(*pi) == hasGfx.end()) { hasGfx.insert(*pi); const float colorMix = min(1.0f, curPower / max(1.0f, weaponDef->shieldPower)); const float3 color = (weaponDef->shieldGoodColor * colorMix) + (weaponDef->shieldBadColor * (1.0f - colorMix)); SAFE_NEW CRepulseGfx(owner, *pi, radius, color); } } if (defHitFrames > 0) { hitFrames = defHitFrames; } } else { // kill the projectile if (owner->UseEnergy(weaponDef->shieldEnergyUse)) { if (weaponDef->shieldPower != 0) { curPower -= (*pi)->weaponDef->damages[0]; } (*pi)->Collision(owner); if (defHitFrames > 0) { hitFrames = defHitFrames; } } } } else { // Calculate the amount of energy we wanted to pull /* Domipheus: TODO Commented out for now, ShieldRepulse has side effects, design needs altering. if(weaponDef->shieldRepulser) { //bounce the projectile int type=(*pi)->ShieldRepulse(this,weaponPos,weaponDef->shieldForce,weaponDef->shieldMaxSpeed); if (type==1){ gs->Team(owner->team)->energyPullAmount += weaponDef->shieldEnergyUse; } else { gs->Team(owner->team)->energyPullAmount += weaponDef->shieldEnergyUse/30.0f; } } else { //kill the projectile gs->Team(owner->team)->energyPullAmount += weaponDef->shieldEnergyUse; }*/ } } } } lastPower = curPower; wasEnabled = isEnabled; }
/** * @brief Causes this CMobileCAI to execute the attack order c */ void CMobileCAI::ExecuteAttack(Command &c) { assert(owner->unitDef->canAttack); // limit how far away we fly if (tempOrder && (owner->moveState < 2) && orderTarget && LinePointDist(ClosestPointOnLine(commandPos1, commandPos2, owner->pos), commandPos2, orderTarget->pos) > (500 * owner->moveState + owner->maxRange)) { StopMove(); FinishCommand(); return; } // check if we are in direct command of attacker if (!inCommand) { // don't start counting until the owner->AttackGround() order is given owner->commandShotCount = -1; if (c.params.size() == 1) { const int targetID = int(c.params[0]); const bool legalTarget = (targetID >= 0 && targetID < MAX_UNITS); CUnit* targetUnit = (legalTarget)? uh->units[targetID]: 0x0; // check if we have valid target parameter and that we aren't attacking ourselves if (legalTarget && targetUnit != 0x0 && targetUnit != owner) { float3 fix = targetUnit->pos + owner->posErrorVector * 128; float3 diff = float3(fix - owner->pos).Normalize(); if (owner->moveState > 0 || !tempOrder) { SetGoal(fix - diff * targetUnit->radius, owner->pos); } orderTarget = targetUnit; AddDeathDependence(orderTarget); inCommand = true; } else { // unit may not fire on itself, cancel order StopMove(); FinishCommand(); return; } } else { // user gave force-fire attack command float3 pos(c.params[0], c.params[1], c.params[2]); SetGoal(pos, owner->pos); inCommand = true; } } else if ((c.params.size() == 3) && (owner->commandShotCount > 0) && (commandQue.size() > 1)) { // the trailing CMD_SET_WANTED_MAX_SPEED in a command pair does not count if ((commandQue.size() > 2) || (commandQue.back().id != CMD_SET_WANTED_MAX_SPEED)) { StopMove(); FinishCommand(); return; } } // if our target is dead or we lost it then stop attacking // NOTE: unit should actually just continue to target area! if (targetDied || (c.params.size() == 1 && UpdateTargetLostTimer(int(c.params[0])) == 0)) { // cancel keeppointingto StopMove(); FinishCommand(); return; } // user clicked on enemy unit (note that we handle aircrafts slightly differently) if (orderTarget) { //bool b1 = owner->AttackUnit(orderTarget, c.id == CMD_DGUN); bool b2 = false; bool b3 = false; bool b4 = false; float edgeFactor = 0.f; // percent offset to target center float3 diff = owner->pos - orderTarget->midPos; if (owner->weapons.size() > 0) { if (!(c.options & ALT_KEY) && SkipParalyzeTarget(orderTarget)) { StopMove(); FinishCommand(); return; } CWeapon* w = owner->weapons.front(); // if we have at least one weapon then check if we // can hit target with our first (meanest) one b2 = w->TryTargetRotate(orderTarget, c.id == CMD_DGUN); b3 = Square(w->range - (w->relWeaponPos).Length()) > (orderTarget->pos.SqDistance(owner->pos)); b4 = w->TryTargetHeading(GetHeadingFromVector(-diff.x, -diff.z), orderTarget->pos, orderTarget != NULL); edgeFactor = fabs(w->targetBorder); } double diffLength2d = diff.Length2D(); // if w->AttackUnit() returned true then we are already // in range with our biggest weapon so stop moving // also make sure that we're not locked in close-in/in-range state loop // due to rotates invoked by in-range or out-of-range states if (b2) { if (!(tempOrder && owner->moveState == 0) && (diffLength2d * 1.4f > owner->maxRange - orderTarget->speed.SqLength() / owner->unitDef->maxAcc) && b4 && diff.dot(orderTarget->speed) < 0) { SetGoal(owner->pos + (orderTarget->speed * 80), owner->pos, SQUARE_SIZE, orderTarget->speed.Length() * 1.1f); } else { StopMove(); // FIXME kill magic frame number if (gs->frameNum > lastCloseInTry + MAX_CLOSE_IN_RETRY_TICKS) { owner->moveType->KeepPointingTo(orderTarget->midPos, std::min((float) (owner->losRadius * SQUARE_SIZE * 2), owner->maxRange * 0.9f), true); } } owner->AttackUnit(orderTarget, c.id == CMD_DGUN); } // if ((our movetype has type TAAirMoveType and length of 2D vector from us to target // less than 90% of our maximum range) OR squared length of 2D vector from us to target // less than 1024) then we are close enough else if(diffLength2d < (owner->maxRange * 0.9f)){ if (dynamic_cast<CTAAirMoveType*>(owner->moveType) || (diff.SqLength2D() < 1024)) { StopMove(); owner->moveType->KeepPointingTo(orderTarget->midPos, std::min((float) (owner->losRadius * SQUARE_SIZE * 2), owner->maxRange * 0.9f), true); } else if(tempOrder && owner->moveState == 0){ SetGoal(lastUserGoal, owner->pos); } // if (((first weapon range minus first weapon length greater than distance to target) // and length of 2D vector from us to target less than 90% of our maximum range) // then we are close enough, but need to move sideways to get a shot. //assumption is flawed: The unit may be aiming or otherwise unable to shoot else if (owner->unitDef->strafeToAttack && b3 && diffLength2d < (owner->maxRange * 0.9f)) { moveDir ^= (owner->moveType->progressState == AMoveType::Failed); float sin = moveDir ? 3.0/5 : -3.0/5; float cos = 4.0/5; float3 goalDiff(0, 0, 0); goalDiff.x = diff.dot(float3(cos, 0, -sin)); goalDiff.z = diff.dot(float3(sin, 0, cos)); goalDiff *= (diffLength2d < (owner->maxRange * 0.3f)) ? 1/cos : cos; goalDiff += orderTarget->pos; SetGoal(goalDiff, owner->pos); } } // if 2D distance of (target position plus attacker error vector times 128) // to goal position greater than // (10 plus 20% of 2D distance between attacker and target) then we need to close // in on target more else if ((orderTarget->pos + owner->posErrorVector * 128).SqDistance2D(goalPos) > Square(10 + orderTarget->pos.distance2D(owner->pos) * 0.2f)) { // if the target isn't in LOS, go to its approximate position // otherwise try to go precisely to the target // this should fix issues with low range weapons (mainly melee) float3 fix = orderTarget->pos + (orderTarget->losStatus[owner->allyteam] & LOS_INLOS ? float3(0.f,0.f,0.f) : owner->posErrorVector * 128); float3 norm = float3(fix - owner->pos).Normalize(); float3 goal = fix - norm*(orderTarget->radius*edgeFactor*0.8f); SetGoal(goal, owner->pos); if (lastCloseInTry < gs->frameNum + MAX_CLOSE_IN_RETRY_TICKS) lastCloseInTry = gs->frameNum; } } // user is attacking ground else { const float3 pos(c.params[0], c.params[1], c.params[2]); const float3 diff = owner->pos - pos; if (owner->weapons.size() > 0) { // if we have at least one weapon then check if // we can hit position with our first (assumed // to be meanest) one CWeapon* w = owner->weapons.front(); // XXX hack - dgun overrides any checks if (c.id == CMD_DGUN) { float rr = owner->maxRange * owner->maxRange; for (vector<CWeapon*>::iterator it = owner->weapons.begin(); it != owner->weapons.end(); ++it) { if (dynamic_cast<CDGunWeapon*>(*it)) rr = (*it)->range * (*it)->range; } if (diff.SqLength() < rr) { StopMove(); owner->AttackGround(pos, c.id == CMD_DGUN); owner->moveType->KeepPointingTo(pos, owner->maxRange * 0.9f, true); } } else { const bool inAngle = w->TryTargetRotate(pos, c.id == CMD_DGUN); const bool inRange = diff.Length2D() < (w->range - (w->relWeaponPos).Length2D()); if (inAngle || inRange) { StopMove(); owner->AttackGround(pos, c.id == CMD_DGUN); owner->moveType->KeepPointingTo(pos, owner->maxRange * 0.9f, true); } } } else if (diff.SqLength2D() < 1024) { StopMove(); owner->moveType->KeepPointingTo(pos, owner->maxRange * 0.9f, true); } // if we are more than 10 units distant from target position then keeping moving closer else if (pos.SqDistance2D(goalPos) > 100) { SetGoal(pos, owner->pos); } } }
void CBasicMapDamage::Explosion(const float3& pos, float strength, float radius) { if (!pos.IsInMap()) { return; } if (strength < 10.0f || radius < 8.0f) { return; } Explo* e = new Explo; e->pos = pos; e->strength = strength; e->ttl = 10; e->x1 = Clamp<int>((pos.x - radius) / SQUARE_SIZE, 1, mapDims.mapxm1); e->x2 = Clamp<int>((pos.x + radius) / SQUARE_SIZE, 1, mapDims.mapxm1); e->y1 = Clamp<int>((pos.z - radius) / SQUARE_SIZE, 1, mapDims.mapym1); e->y2 = Clamp<int>((pos.z + radius) / SQUARE_SIZE, 1, mapDims.mapym1); e->squares.reserve((e->y2 - e->y1 + 1) * (e->x2 - e->x1 + 1)); const float* curHeightMap = readMap->GetCornerHeightMapSynced(); const float* orgHeightMap = readMap->GetOriginalHeightMapSynced(); const unsigned char* typeMap = readMap->GetTypeMapSynced(); const float baseStrength = -math::pow(strength, 0.6f) * 3 / mapHardness; const float invRadius = 1.0f / radius; for (int y = e->y1; y <= e->y2; ++y) { for (int x = e->x1; x <= e->x2; ++x) { const CSolidObject* so = groundBlockingObjectMap->GroundBlockedUnsafe(y * mapDims.mapx + x); // do not change squares with buildings on them here if (so && so->blockHeightChanges) { e->squares.push_back(0.0f); continue; } // calculate the distance and normalize it const float expDist = pos.distance2D(float3(x * SQUARE_SIZE, 0, y * SQUARE_SIZE)); const float relDist = std::min(1.0f, expDist * invRadius); const unsigned int tableIdx = relDist * CRATER_TABLE_SIZE; float dif = baseStrength; dif *= craterTable[tableIdx]; dif *= invHardness[typeMap[(y / 2) * mapDims.hmapx + x / 2]]; // FIXME: compensate for flattened ground under dead buildings const float prevDif = curHeightMap[y * mapDims.mapxp1 + x] - orgHeightMap[y * mapDims.mapxp1 + x]; if (prevDif * dif > 0.0f) { dif /= math::fabs(prevDif) * 0.1f + 1; } e->squares.push_back(dif); if (dif < -0.3f && strength > 200.0f) { grassDrawer->RemoveGrass(float3(x * SQUARE_SIZE, 0.0f, y * SQUARE_SIZE)); } } } // calculate how much to offset the buildings in the explosion radius with // (while still keeping the ground below them flat) const std::vector<CUnit*>& units = quadField->GetUnitsExact(pos, radius); for (const CUnit* unit: units) { if (!unit->blockHeightChanges) { continue; } if (!unit->IsBlocking()) { continue; } float totalDif = 0.0f; for (int z = unit->mapPos.y; z < unit->mapPos.y + unit->zsize; z++) { for (int x = unit->mapPos.x; x < unit->mapPos.x + unit->xsize; x++) { // calculate the distance and normalize it const float expDist = pos.distance2D(float3(x * SQUARE_SIZE, 0, z * SQUARE_SIZE)); const float relDist = std::min(1.0f, expDist * invRadius); const unsigned int tableIdx = relDist * CRATER_TABLE_SIZE; float dif = baseStrength * craterTable[tableIdx] * invHardness[typeMap[(z / 2) * mapDims.hmapx + x / 2]]; const float prevDif = curHeightMap[z * mapDims.mapxp1 + x] - orgHeightMap[z * mapDims.mapxp1 + x]; if (prevDif * dif > 0.0f) { dif /= math::fabs(prevDif) * 0.1f + 1; } totalDif += dif; } } totalDif /= (unit->xsize * unit->zsize); if (totalDif != 0.0f) { ExploBuilding eb; eb.id = unit->id; eb.dif = totalDif; eb.tx1 = unit->mapPos.x; eb.tx2 = unit->mapPos.x + unit->xsize; eb.tz1 = unit->mapPos.y; eb.tz2 = unit->mapPos.y + unit->zsize; e->buildings.push_back(eb); } } explosions.push_back(e); }
void CMissileProjectile::Update() { if (--ttl > 0) { if (!luaMoveCtrl) { if (curSpeed < maxSpeed) { curSpeed += weaponDef->weaponacceleration; } float3 targSpeed(ZeroVector); if (weaponDef->tracks && target) { CSolidObject* so = dynamic_cast<CSolidObject*>(target); CWeaponProjectile* po = dynamic_cast<CWeaponProjectile*>(target); targetPos = target->pos; if (so) { targetPos = so->aimPos; targSpeed = so->speed; if (owner()) { CUnit* u = dynamic_cast<CUnit*>(so); if (u) { targetPos = CGameHelper::GetUnitErrorPos(u, owner()->allyteam, true); } } } if (po) { targSpeed = po->speed; } } if (isWobbling) { --wobbleTime; if (wobbleTime == 0) { float3 newWob = gs->randVector(); wobbleDif = (newWob - wobbleDir) * (1.0f / 16); wobbleTime = 16; } wobbleDir += wobbleDif; dir += wobbleDir * weaponDef->wobble * (owner()? (1.0f - owner()->limExperience * 0.5f): 1); dir.Normalize(); } if (isDancing) { --danceTime; if (danceTime <= 0) { danceMove = gs->randVector() * weaponDef->dance - danceCenter; danceCenter += danceMove; danceTime = 8; } pos += danceMove; } const float3 orgTargPos = targetPos; const float3 targetDir = (targetPos - pos).SafeNormalize(); const float dist = pos.distance(targetPos) + 0.1f; if (extraHeightTime > 0) { extraHeight -= extraHeightDecay; --extraHeightTime; targetPos.y += extraHeight; if (dir.y <= 0.0f) { // missile has reached apex, smoothly transition // to targetDir (can still overshoot when target // is too close or height difference too large) const float horDiff = (targetPos - pos).Length2D() + 0.01f; const float verDiff = (targetPos.y - pos.y) + 0.01f; const float dirDiff = math::fabs(targetDir.y - dir.y); const float ratio = math::fabs(verDiff / horDiff); dir.y -= (dirDiff * ratio); } else { // missile is still ascending dir.y -= (extraHeightDecay / dist); } } float3 dif = (targetPos + targSpeed * (dist / maxSpeed) * 0.7f - pos).SafeNormalize(); float3 dif2 = dif - dir; if (dif2.SqLength() < Square(weaponDef->turnrate)) { dir = dif; } else { dif2 -= (dir * (dif2.dot(dir))); dif2.SafeNormalize(); dir += (dif2 * weaponDef->turnrate); dir.SafeNormalize(); } targetPos = orgTargPos; speed = dir * curSpeed; } gCEG->Explosion(cegID, pos, ttl, areaOfEffect, NULL, 0.0f, NULL, dir); } else { if (weaponDef->selfExplode) { Collision(); } else { // only when TTL <= 0 do we (missiles) // get influenced by gravity and drag if (!luaMoveCtrl) { speed *= 0.98f; speed.y += mygravity; dir = speed; dir.SafeNormalize(); } } } if (!luaMoveCtrl) { pos += speed; } age++; numParts++; if (weaponDef->visuals.smokeTrail && !(age & 7)) { CSmokeTrailProjectile* tp = new CSmokeTrailProjectile( pos, oldSmoke, dir, oldDir, owner(), age == 8, false, 7, SMOKE_TIME, 0.6f, drawTrail, 0, weaponDef->visuals.texture2 ); oldSmoke = pos; oldDir = dir; numParts = 0; useAirLos = tp->useAirLos; if (!drawTrail) { const float3 camDir = (pos - camera->pos).ANormalize(); if ((camera->pos.distance(pos) * 0.2f + (1 - math::fabs(camDir.dot(dir))) * 3000) > 300) { drawTrail = true; } } } UpdateInterception(); UpdateGroundBounce(); }
void CAdvTreeDrawer::DrawShadowPass() { const float treeDistance = oldTreeDistance; const int activeFarTex = (camera->forward.z < 0.0f)? treeGen->farTex[0] : treeGen->farTex[1]; const bool drawDetailed = (treeDistance >= 4.0f); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, activeFarTex); glEnable(GL_TEXTURE_2D); glEnable(GL_ALPHA_TEST); glDisable(GL_CULL_FACE); glPolygonOffset(1, 1); glEnable(GL_POLYGON_OFFSET_FILL); CAdvTreeSquareDrawer_SP drawer; const int cx = drawer.cx = (int)(camera->pos.x / (SQUARE_SIZE * TREE_SQUARE_SIZE)); const int cy = drawer.cy = (int)(camera->pos.z / (SQUARE_SIZE * TREE_SQUARE_SIZE)); drawer.drawDetailed = drawDetailed; drawer.td = this; drawer.treeDistance = treeDistance * SQUARE_SIZE * TREE_SQUARE_SIZE; Shader::IProgramObject* po = NULL; GML_STDMUTEX_LOCK(tree); // DrawShadowPass // draw with extraSize=1 readmap->GridVisibility(camera, TREE_SQUARE_SIZE, drawer.treeDistance * 2.0f, &drawer, 1); if (drawDetailed) { const int xstart = std::max( 0, cx - 2); const int xend = std::min(gs->mapx / TREE_SQUARE_SIZE - 1, cx + 2); const int ystart = std::max( 0, cy - 2); const int yend = std::min(gs->mapy / TREE_SQUARE_SIZE - 1, cy + 2); glBindTexture(GL_TEXTURE_2D, treeGen->barkTex); glEnable(GL_TEXTURE_2D); po = shadowHandler->GetShadowGenProg(CShadowHandler::SHADOWGEN_PROGRAM_TREE_NEAR); po->Enable(); if (globalRendering->haveGLSL) { po->SetUniform3fv(1, &camera->right[0]); po->SetUniform3fv(2, &camera->up[0]); } else { po->SetUniformTarget(GL_VERTEX_PROGRAM_ARB); po->SetUniform4f(13, camera->right.x, camera->right.y, camera->right.z, 0.0f); po->SetUniform4f(9, camera->up.x, camera->up.y, camera->up.z, 0.0f); po->SetUniform4f(11, 1.0f, 1.0f, 1.0f, 0.85f ); po->SetUniform4f(12, 0.0f, 0.0f, 0.0f, 0.20f * (1.0f / MAX_TREE_HEIGHT)); // w = alpha/height modifier } glAlphaFunc(GL_GREATER, 0.5f); glEnable(GL_ALPHA_TEST); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); CVertexArray* va = GetVertexArray(); va->Initialize(); static FadeTree fadeTrees[3000]; FadeTree* pFT = fadeTrees; for (TreeSquareStruct* pTSS = trees + (ystart * treesX); pTSS <= trees + (yend * treesX); pTSS += treesX) { for (TreeSquareStruct* tss = pTSS + xstart; tss <= pTSS + xend; ++tss) { tss->lastSeen = gs->frameNum; va->EnlargeArrays(12 * tss->trees.size(), 0, VA_SIZE_T); //!alloc room for all tree vertexes for (std::map<int, TreeStruct>::iterator ti = tss->trees.begin(); ti != tss->trees.end(); ++ti) { const TreeStruct* ts = &ti->second; const float3 pos(ts->pos); if (!camera->InView(pos + float3(0, MAX_TREE_HEIGHT / 2, 0), MAX_TREE_HEIGHT / 2 + 150)) { continue; } const float camDist = (pos - camera->pos).SqLength(); int type = ts->type; float dy = 0.0f; unsigned int dispList; if (type < 8) { dy = 0.5f; dispList = treeGen->pineDL + type; } else { type -= 8; dy = 0; dispList = treeGen->leafDL + type; } if (camDist < SQUARE_SIZE * SQUARE_SIZE * 110 * 110) { po->SetUniform3f((globalRendering->haveGLSL? 3: 10), pos.x, pos.y, pos.z); glCallList(dispList); } else if (camDist < SQUARE_SIZE * SQUARE_SIZE * 125 * 125) { const float relDist = (pos.distance(camera->pos) - SQUARE_SIZE * 110) / (SQUARE_SIZE * 15); glAlphaFunc(GL_GREATER, 0.8f + relDist * 0.2f); po->SetUniform3f((globalRendering->haveGLSL? 3: 10), pos.x, pos.y, pos.z); glCallList(dispList); glAlphaFunc(GL_GREATER, 0.5f); pFT->pos = pos; pFT->deltaY = dy; pFT->type = type; pFT->relDist = relDist; ++pFT; } else { CAdvTreeDrawer::DrawTreeVertex(va, pos, type * 0.125f, dy, false); } } } } po->SetUniform3f((globalRendering->haveGLSL? 3: 10), 0.0f, 0.0f, 0.0f); for (std::list<FallingTree>::iterator fti = fallingTrees.begin(); fti != fallingTrees.end(); ++fti) { const float3 pos = fti->pos - UpVector * (fti->fallPos * 20); if (camera->InView(pos + float3(0, MAX_TREE_HEIGHT / 2, 0), MAX_TREE_HEIGHT / 2)) { const float ang = fti->fallPos * PI; const float3 yvec(fti->dir.x * sin(ang), cos(ang), fti->dir.z * sin(ang)); const float3 zvec((yvec.cross(float3(1.0f, 0.0f, 0.0f))).ANormalize()); const float3 xvec(zvec.cross(yvec)); CMatrix44f transMatrix(pos, xvec, yvec, zvec); glPushMatrix(); glMultMatrixf(&transMatrix[0]); int type = fti->type; int dispList; if (type < 8) { dispList = treeGen->pineDL + type; } else { type -= 8; dispList = treeGen->leafDL + type; } glCallList(dispList); glPopMatrix(); } } po->Disable(); po = shadowHandler->GetShadowGenProg(CShadowHandler::SHADOWGEN_PROGRAM_TREE_FAR); po->Enable(); glBindTexture(GL_TEXTURE_2D, activeFarTex); va->DrawArrayT(GL_QUADS); for (FadeTree* pFTree = fadeTrees; pFTree < pFT; ++pFTree) { // faded close trees va = GetVertexArray(); va->Initialize(); va->CheckInitSize(12 * VA_SIZE_T); CAdvTreeDrawer::DrawTreeVertex(va, pFTree->pos, pFTree->type * 0.125f, pFTree->deltaY, false); glAlphaFunc(GL_GREATER, 1.0f - (pFTree->relDist * 0.5f)); va->DrawArrayT(GL_QUADS); } po->Disable(); } glEnable(GL_CULL_FACE); glDisable(GL_POLYGON_OFFSET_FILL); glDisable(GL_TEXTURE_2D); glDisable(GL_ALPHA_TEST); }
float3 ALVecToVec(float3 const & v) { return float3(v.x(), v.y(), -v.z()); }
void CFeature::Initialize(const float3& _pos, const FeatureDef* _def, short int _heading, int facing, int _team, int _allyteam, const UnitDef* _udef, const float3& speed, int _smokeTime) { def = _def; udef = _udef; defID = def->id; heading = _heading; buildFacing = facing; team = _team; allyteam = _allyteam; emitSmokeTime = _smokeTime; mass = def->mass; crushResistance = def->crushResistance; health = def->maxHealth; blocking = def->blocking; xsize = ((facing & 1) == 0) ? def->xsize : def->zsize; zsize = ((facing & 1) == 1) ? def->xsize : def->zsize; noSelect = def->noSelect; if (def->drawType == DRAWTYPE_MODEL) { if ((model = def->LoadModel()) == NULL) { LOG_L(L_ERROR, "Features: Couldn't load model for %s", def->name.c_str()); } else { SetMidAndAimPos(model->relMidPos, model->relMidPos, true); SetRadiusAndHeight(model->radius, model->height); } } else { if (def->drawType >= DRAWTYPE_TREE) { // LoadFeaturesFromMap() doesn't set a scale for trees SetMidAndAimPos(UpVector * TREE_RADIUS, UpVector * TREE_RADIUS, true); SetRadiusAndHeight(TREE_RADIUS, TREE_RADIUS * 2.0f); } } // note: gets deleted in ~CSolidObject collisionVolume = new CollisionVolume(def->collisionVolume, radius); Move3D(_pos.cClampInMap(), false); UpdateMidAndAimPos(); CalculateTransform(); featureHandler->AddFeature(this); qf->AddFeature(this); // maybe should not be here, but it prevents crashes caused by team = -1 ChangeTeam(team); if (blocking) { Block(); } if (def->floating) { finalHeight = ground->GetHeightAboveWater(pos.x, pos.z); } else { finalHeight = ground->GetHeightReal(pos.x, pos.z); } if (speed != ZeroVector) { deathSpeed = speed; } reachedFinalPos = (speed == ZeroVector && pos.y == finalHeight); }
void CAdvTreeDrawer::Draw(float treeDistance, bool drawReflection) { const int activeFarTex = (camera->forward.z < 0.0f)? treeGen->farTex[0]: treeGen->farTex[1]; const bool drawDetailed = ((treeDistance >= 4.0f) || drawReflection); CBaseGroundDrawer* gd = readmap->GetGroundDrawer(); Shader::IProgramObject* treeShader = NULL; const CMapInfo::light_t& light = mapInfo->light; glEnable(GL_ALPHA_TEST); glEnable(GL_TEXTURE_2D); ISky::SetupFog(); if (shadowHandler->shadowsLoaded && !gd->DrawExtraTex()) { glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, activeFarTex); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, shadowHandler->shadowTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_ALPHA); treeShader = treeShaders[TREE_PROGRAM_DIST_SHADOW]; treeShader->Enable(); if (globalRendering->haveGLSL) { treeShader->SetUniformMatrix4fv(7, false, &shadowHandler->shadowMatrix.m[0]); treeShader->SetUniform4fv(8, &(shadowHandler->GetShadowParams().x)); } else { treeShader->SetUniformTarget(GL_FRAGMENT_PROGRAM_ARB); treeShader->SetUniform4f(10, light.groundAmbientColor.x, light.groundAmbientColor.y, light.groundAmbientColor.z, 1.0f); treeShader->SetUniform4f(11, 0.0f, 0.0f, 0.0f, 1.0f - (sky->GetLight()->GetGroundShadowDensity() * 0.5f)); treeShader->SetUniformTarget(GL_VERTEX_PROGRAM_ARB); glMatrixMode(GL_MATRIX0_ARB); glLoadMatrixf(shadowHandler->shadowMatrix.m); glMatrixMode(GL_MODELVIEW); } } else { glBindTexture(GL_TEXTURE_2D, activeFarTex); } const int cx = int(camera->pos.x / (SQUARE_SIZE * TREE_SQUARE_SIZE)); const int cy = int(camera->pos.z / (SQUARE_SIZE * TREE_SQUARE_SIZE)); CAdvTreeSquareDrawer drawer(this, cx, cy, treeDistance * SQUARE_SIZE * TREE_SQUARE_SIZE, drawDetailed); GML_STDMUTEX_LOCK(tree); // Draw oldTreeDistance = treeDistance; // draw far-trees using map-dependent grid-visibility readmap->GridVisibility(camera, TREE_SQUARE_SIZE, drawer.treeDistance * 2.0f, &drawer); if (drawDetailed) { // draw near-trees const int xstart = std::max( 0, cx - 2); const int xend = std::min(gs->mapx / TREE_SQUARE_SIZE - 1, cx + 2); const int ystart = std::max( 0, cy - 2); const int yend = std::min(gs->mapy / TREE_SQUARE_SIZE - 1, cy + 2); if (shadowHandler->shadowsLoaded && !gd->DrawExtraTex()) { treeShader->Disable(); treeShader = treeShaders[TREE_PROGRAM_NEAR_SHADOW]; treeShader->Enable(); if (globalRendering->haveGLSL) { treeShader->SetUniformMatrix4fv(7, false, &shadowHandler->shadowMatrix.m[0]); treeShader->SetUniform4fv(8, &(shadowHandler->GetShadowParams().x)); } glActiveTexture(GL_TEXTURE1); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, treeGen->barkTex); glActiveTexture(GL_TEXTURE0); } else { glBindTexture(GL_TEXTURE_2D, treeGen->barkTex); treeShader = treeShaders[TREE_PROGRAM_NEAR_BASIC]; treeShader->Enable(); if (!globalRendering->haveGLSL) { const int mx = gs->pwr2mapx * SQUARE_SIZE; const int my = gs->pwr2mapy * SQUARE_SIZE; treeShader->SetUniformTarget(GL_VERTEX_PROGRAM_ARB); treeShader->SetUniform4f(15, 1.0f / mx, 1.0f / my, 1.0f / mx, 1.0f); } } if (globalRendering->haveGLSL) { treeShader->SetUniform3fv(0, &camera->right[0]); treeShader->SetUniform3fv(1, &camera->up[0]); treeShader->SetUniform2f(5, 0.20f * (1.0f / MAX_TREE_HEIGHT), 0.85f); } else { treeShader->SetUniformTarget(GL_VERTEX_PROGRAM_ARB); treeShader->SetUniform3f(13, camera->right.x, camera->right.y, camera->right.z); treeShader->SetUniform3f( 9, camera->up.x, camera->up.y, camera->up.z ); treeShader->SetUniform4f(11, light.groundSunColor.x, light.groundSunColor.y, light.groundSunColor.z, 0.85f); treeShader->SetUniform4f(14, light.groundAmbientColor.x, light.groundAmbientColor.y, light.groundAmbientColor.z, 0.85f); treeShader->SetUniform4f(12, 0.0f, 0.0f, 0.0f, 0.20f * (1.0f / MAX_TREE_HEIGHT)); // w = alpha/height modifier } glAlphaFunc(GL_GREATER, 0.5f); glDisable(GL_BLEND); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); CVertexArray* va = GetVertexArray(); va->Initialize(); static FadeTree fadeTrees[3000]; FadeTree* pFT = fadeTrees; for (TreeSquareStruct* pTSS = trees + (ystart * treesX); pTSS <= trees + (yend * treesX); pTSS += treesX) { for (TreeSquareStruct* tss = pTSS + xstart; tss <= (pTSS + xend); ++tss) { tss->lastSeen = gs->frameNum; va->EnlargeArrays(12 * tss->trees.size(), 0, VA_SIZE_T); //!alloc room for all tree vertexes for (std::map<int, TreeStruct>::iterator ti = tss->trees.begin(); ti != tss->trees.end(); ++ti) { const TreeStruct* ts = &ti->second; const float3 pos(ts->pos); if (!camera->InView(pos + float3(0.0f, MAX_TREE_HEIGHT / 2.0f, 0.0f), MAX_TREE_HEIGHT / 2.0f)) { continue; } const float camDist = (pos - camera->pos).SqLength(); int type = ts->type; float dy = 0.0f; unsigned int dispList; if (type < 8) { dy = 0.5f; dispList = treeGen->pineDL + type; } else { type -= 8; dy = 0.0f; dispList = treeGen->leafDL + type; } if (camDist < (SQUARE_SIZE * SQUARE_SIZE * 110 * 110)) { // draw detailed near-distance tree (same as mid-distance trees without alpha) treeShader->SetUniform3f(((globalRendering->haveGLSL)? 2: 10), pos.x, pos.y, pos.z); glCallList(dispList); } else if (camDist < (SQUARE_SIZE * SQUARE_SIZE * 125 * 125)) { // draw mid-distance tree const float relDist = (pos.distance(camera->pos) - SQUARE_SIZE * 110) / (SQUARE_SIZE * 15); treeShader->SetUniform3f(((globalRendering->haveGLSL)? 2: 10), pos.x, pos.y, pos.z); glAlphaFunc(GL_GREATER, 0.8f + relDist * 0.2f); glCallList(dispList); glAlphaFunc(GL_GREATER, 0.5f); // save for second pass pFT->pos = pos; pFT->deltaY = dy; pFT->type = type; pFT->relDist = relDist; ++pFT; } else { // draw far-distance tree CAdvTreeDrawer::DrawTreeVertex(va, pos, type * 0.125f, dy, false); } } } } // reset the world-offset treeShader->SetUniform3f(((globalRendering->haveGLSL)? 2: 10), 0.0f, 0.0f, 0.0f); // draw trees that have been marked as falling for (std::list<FallingTree>::iterator fti = fallingTrees.begin(); fti != fallingTrees.end(); ++fti) { const float3 pos = fti->pos - UpVector * (fti->fallPos * 20); if (camera->InView(pos + float3(0.0f, MAX_TREE_HEIGHT / 2, 0.0f), MAX_TREE_HEIGHT / 2.0f)) { const float ang = fti->fallPos * PI; const float3 yvec(fti->dir.x * sin(ang), cos(ang), fti->dir.z * sin(ang)); const float3 zvec((yvec.cross(float3(-1.0f, 0.0f, 0.0f))).ANormalize()); const float3 xvec(yvec.cross(zvec)); CMatrix44f transMatrix(pos, xvec, yvec, zvec); glPushMatrix(); glMultMatrixf(&transMatrix[0]); int type = fti->type; int dispList = 0; if (type < 8) { dispList = treeGen->pineDL + type; } else { type -= 8; dispList = treeGen->leafDL + type; } glCallList(dispList); glPopMatrix(); } } if (shadowHandler->shadowsLoaded && !gd->DrawExtraTex()) { treeShader->Disable(); treeShader = treeShaders[TREE_PROGRAM_DIST_SHADOW]; treeShader->Enable(); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, activeFarTex); glActiveTexture(GL_TEXTURE0); } else { treeShader->Disable(); glBindTexture(GL_TEXTURE_2D, activeFarTex); } // draw far-distance trees va->DrawArrayT(GL_QUADS); // draw faded mid-distance trees for (FadeTree* pFTree = fadeTrees; pFTree < pFT; ++pFTree) { va = GetVertexArray(); va->Initialize(); va->CheckInitSize(12 * VA_SIZE_T); CAdvTreeDrawer::DrawTreeVertex(va, pFTree->pos, pFTree->type * 0.125f, pFTree->deltaY, false); glAlphaFunc(GL_GREATER, 1.0f - (pFTree->relDist * 0.5f)); va->DrawArrayT(GL_QUADS); } } if (shadowHandler->shadowsLoaded && !gd->DrawExtraTex()) { treeShader->Disable(); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, 0); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE); glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE); } else { glBindTexture(GL_TEXTURE_2D, 0); } glDisable(GL_TEXTURE_2D); glDisable(GL_FOG); glDisable(GL_ALPHA_TEST); // clean out squares from memory that are no longer visible const int startClean = lastListClean * 20 % (nTrees); const int endClean = gs->frameNum * 20 % (nTrees); lastListClean = gs->frameNum; if (startClean > endClean) { for (TreeSquareStruct* pTSS = trees + startClean; pTSS < (trees + nTrees); ++pTSS) { if ((pTSS->lastSeen < gs->frameNum - 50) && pTSS->dispList) { glDeleteLists(pTSS->dispList, 1); pTSS->dispList = 0; } if ((pTSS->lastSeenFar < (gs->frameNum - 50)) && pTSS->farDispList) { glDeleteLists(pTSS->farDispList, 1); pTSS->farDispList = 0; } } for (TreeSquareStruct* pTSS = trees; pTSS < (trees + endClean); ++pTSS) { if ((pTSS->lastSeen < (gs->frameNum - 50)) && pTSS->dispList) { glDeleteLists(pTSS->dispList, 1); pTSS->dispList = 0; } if ((pTSS->lastSeenFar < (gs->frameNum - 50)) && pTSS->farDispList) { glDeleteLists(pTSS->farDispList, 1); pTSS->farDispList = 0; } } } else { for (TreeSquareStruct* pTSS = trees + startClean; pTSS < (trees + endClean); ++pTSS) { if ((pTSS->lastSeen < (gs->frameNum - 50)) && pTSS->dispList) { glDeleteLists(pTSS->dispList, 1); pTSS->dispList = 0; } if ((pTSS->lastSeenFar < (gs->frameNum - 50)) && pTSS->farDispList) { glDeleteLists(pTSS->farDispList, 1); pTSS->farDispList = 0; } } } }
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; } }
bool Triangle::IsDegenerate(const float3 &a, const float3 &b, const float3 &c, float epsilon) { return a.Equals(b, epsilon) || a.Equals(c, epsilon) || b.Equals(c, epsilon); }
bool CHoverAirMoveType::Update() { float3& pos = owner->pos; float3& speed = owner->speed; AAirMoveType::Update(); if (owner->stunned || owner->beingBuilt) { wantedSpeed = ZeroVector; wantToStop = true; } // Allow us to stop if wanted if (wantToStop) { ExecuteStop(); } const float3 lastSpeed = speed; if (owner->fpsControlPlayer != NULL) { SetState(AIRCRAFT_FLYING); const FPSUnitController& con = owner->fpsControlPlayer->fpsController; const float3 forward = con.viewDir; const float3 right = forward.cross(UpVector); const float3 nextPos = pos + speed; float3 flatForward = forward; flatForward.y = 0.0f; flatForward.Normalize(); wantedSpeed = ZeroVector; if (con.forward) wantedSpeed += flatForward; if (con.back ) wantedSpeed -= flatForward; if (con.right ) wantedSpeed += right; if (con.left ) wantedSpeed -= right; wantedSpeed.Normalize(); wantedSpeed *= maxSpeed; if (!nextPos.IsInBounds()) { speed = ZeroVector; } UpdateAirPhysics(); wantedHeading = GetHeadingFromVector(flatForward.x, flatForward.z); } else { if (reservedPad != NULL) { MoveToRepairPad(); if (padStatus >= 1) { flyState = FLY_LANDING; } } // Main state handling switch (aircraftState) { case AIRCRAFT_LANDED: UpdateLanded(); break; case AIRCRAFT_TAKEOFF: UpdateTakeoff(); break; case AIRCRAFT_FLYING: UpdateFlying(); break; case AIRCRAFT_LANDING: UpdateLanding(); break; case AIRCRAFT_HOVERING: UpdateHovering(); break; case AIRCRAFT_CRASHING: break; } } // Banking requires deltaSpeed.y = 0 deltaSpeed = speed - lastSpeed; deltaSpeed.y = 0.0f; // Turn and bank and move; update dirs UpdateHeading(); UpdateBanking(aircraftState == AIRCRAFT_HOVERING); return (HandleCollisions()); }
void CGroundDecalHandler::AddExplosion(float3 pos, float damage, float radius) { if(decalLevel==0) return; float height=pos.y-ground->GetHeight2(pos.x,pos.z); if(height>=radius) return; pos.y-=height; radius-=height; if(radius<5) return; if(damage>radius*30) damage=radius*30; damage*=(radius)/(radius+height); if(radius>damage*0.25) radius=damage*0.25; if(damage>400) damage=400+sqrt(damage-399); pos.CheckInBounds(); Scar* s=new Scar; s->pos=pos; s->radius=radius*1.4; s->creationTime=gs->frameNum; s->startAlpha=max(50.f,min(255.f,damage)); float lifeTime=decalLevel*(damage)*3; s->alphaFalloff=s->startAlpha/(lifeTime); s->lifeTime=(int)(gs->frameNum+lifeTime); s->texOffsetX=(gu->usRandInt()&128)?0:0.5f; s->texOffsetY=(gu->usRandInt()&128)?0:0.5f; s->x1=(int)max(0.f,(pos.x-radius)/16.0f); s->x2=(int)min(float(gs->hmapx-1),(pos.x+radius)/16.0f+1); s->y1=(int)max(0.f,(pos.z-radius)/16.0f); s->y2=(int)min(float(gs->hmapy-1),(pos.z+radius)/16.0f+1); s->basesize=(s->x2-s->x1)*(s->y2-s->y1); s->overdrawn=0; s->lastTest=0; TestOverlaps(s); int x1=s->x1/16; int x2=min(scarFieldX-1,s->x2/16); int y1=s->y1/16; int y2=min(scarFieldY-1,s->y2/16); for(int y=y1;y<=y2;++y){ for(int x=x1;x<=x2;++x){ std::set<Scar*>* quad=&scarField[y*scarFieldX+x]; quad->insert(s); } } scars.push_back(s); }
void CPlasmaRepulser::Update(void) { const int defHitFrames = weaponDef->visibleShieldHitFrames; const bool couldBeVisible = (weaponDef->visibleShield || (defHitFrames > 0)); const int defRechargeDelay = weaponDef->shieldRechargeDelay; rechargeDelay -= (rechargeDelay > 0) ? 1 : 0; if (startShowingShield) { // one-time iteration when shield first goes online // (adds the projectile parts, this assumes owner is // not mobile) startShowingShield = false; if (couldBeVisible) { // 32 parts for (int y = 0; y < 16; y += 4) { for (int x = 0; x < 32; x += 4) { visibleShieldParts.push_back( new CShieldPartProjectile(owner->pos, x, y, radius, weaponDef->shieldBadColor, weaponDef->shieldAlpha, weaponDef->visuals.texture1, owner) ); } } } } if (isEnabled && (curPower < weaponDef->shieldPower) && rechargeDelay <= 0) { if (owner->UseEnergy(weaponDef->shieldPowerRegenEnergy * (1.0f / 30.0f))) { curPower += weaponDef->shieldPowerRegen * (1.0f / 30.0f); } } weaponPos = owner->pos + (owner->frontdir * relWeaponPos.z) + (owner->updir * relWeaponPos.y) + (owner->rightdir * relWeaponPos.x); if (couldBeVisible) { float drawAlpha = 0.0f; if (hitFrames > 0) { drawAlpha += float(hitFrames) / float(defHitFrames); hitFrames--; } if (weaponDef->visibleShield) { drawAlpha += 1.0f; } drawAlpha = std::min(1.0f, drawAlpha * weaponDef->shieldAlpha); const bool drawMe = (drawAlpha > 0.0f); if (drawMe || wasDrawn) { const float colorMix = std::min(1.0f, curPower / std::max(1.0f, weaponDef->shieldPower)); const float3 color = (weaponDef->shieldGoodColor * colorMix) + (weaponDef->shieldBadColor * (1.0f - colorMix)); std::list<CShieldPartProjectile*>::iterator si; for (si = visibleShieldParts.begin(); si != visibleShieldParts.end(); ++si) { CShieldPartProjectile* part = *si; part->centerPos = weaponPos; part->color = color; if (isEnabled) { part->baseAlpha = drawAlpha; } else { part->baseAlpha = 0.0f; } } } wasDrawn = drawMe; } if (isEnabled) { for (std::list<CWeaponProjectile*>::iterator pi=incoming.begin();pi!=incoming.end();++pi) { const float3 dif = (*pi)->pos-owner->pos; if ((*pi)->checkCol && dif.SqLength()<sqRadius && curPower > (*pi)->weaponDef->damages[0]) { if (teamHandler->Team(owner->team)->energy > weaponDef->shieldEnergyUse) { rechargeDelay = defRechargeDelay; if (weaponDef->shieldRepulser) { // bounce the projectile const int type = (*pi)->ShieldRepulse(this, weaponPos, weaponDef->shieldForce, weaponDef->shieldMaxSpeed); if (type == 0) { continue; } else if (type == 1) { owner->UseEnergy(weaponDef->shieldEnergyUse); if (weaponDef->shieldPower != 0) { curPower -= (*pi)->weaponDef->damages[0]; } } else { owner->UseEnergy(weaponDef->shieldEnergyUse / 30.0f); if (weaponDef->shieldPower != 0) { curPower -= (*pi)->weaponDef->damages[0] / 30.0f; } } if (weaponDef->visibleShieldRepulse) { std::list<CWeaponProjectile*>::iterator i; for (i=hasGfx.begin();i!=hasGfx.end();i++) if (*i==*pi) { break; } if (i == hasGfx.end()) { hasGfx.insert(hasGfx.end(),*pi); const float colorMix = std::min(1.0f, curPower / std::max(1.0f, weaponDef->shieldPower)); const float3 color = (weaponDef->shieldGoodColor * colorMix) + (weaponDef->shieldBadColor * (1.0f - colorMix)); new CRepulseGfx(owner, *pi, radius, color); } } if (defHitFrames > 0) { hitFrames = defHitFrames; } } else { // kill the projectile if (owner->UseEnergy(weaponDef->shieldEnergyUse)) { if (weaponDef->shieldPower != 0) { curPower -= (*pi)->weaponDef->damages[0]; } (*pi)->Collision(owner); if (defHitFrames > 0) { hitFrames = defHitFrames; } } } } else { // Calculate the amount of energy we wanted to pull /* Domipheus: TODO Commented out for now, ShieldRepulse has side effects, design needs altering. if(weaponDef->shieldRepulser) { //bounce the projectile int type=(*pi)->ShieldRepulse(this,weaponPos,weaponDef->shieldForce,weaponDef->shieldMaxSpeed); if (type==1){ teamHandler->Team(owner->team)->energyPullAmount += weaponDef->shieldEnergyUse; } else { teamHandler->Team(owner->team)->energyPullAmount += weaponDef->shieldEnergyUse/30.0f; } } else { //kill the projectile teamHandler->Team(owner->team)->energyPullAmount += weaponDef->shieldEnergyUse; }*/ } } } } }
bool AABB::IntersectLineAABB_CPP(const float3 &linePos, const float3 &lineDir, float &tNear, float &tFar) const { assume2(lineDir.IsNormalized(), lineDir, lineDir.LengthSq()); assume2(tNear <= tFar && "AABB::IntersectLineAABB: User gave a degenerate line as input for the intersection test!", tNear, tFar); // The user should have inputted values for tNear and tFar to specify the desired subrange [tNear, tFar] of the line // for this intersection test. // For a Line-AABB test, pass in // tNear = -FLOAT_INF; // tFar = FLOAT_INF; // For a Ray-AABB test, pass in // tNear = 0.f; // tFar = FLOAT_INF; // For a LineSegment-AABB test, pass in // tNear = 0.f; // tFar = LineSegment.Length(); // Test each cardinal plane (X, Y and Z) in turn. if (!EqualAbs(lineDir.x, 0.f)) { float recipDir = RecipFast(lineDir.x); float t1 = (minPoint.x - linePos.x) * recipDir; float t2 = (maxPoint.x - linePos.x) * recipDir; // tNear tracks distance to intersect (enter) the AABB. // tFar tracks the distance to exit the AABB. if (t1 < t2) tNear = Max(t1, tNear), tFar = Min(t2, tFar); else // Swap t1 and t2. tNear = Max(t2, tNear), tFar = Min(t1, tFar); if (tNear > tFar) return false; // Box is missed since we "exit" before entering it. } else if (linePos.x < minPoint.x || linePos.x > maxPoint.x) return false; // The ray can't possibly enter the box, abort. if (!EqualAbs(lineDir.y, 0.f)) { float recipDir = RecipFast(lineDir.y); float t1 = (minPoint.y - linePos.y) * recipDir; float t2 = (maxPoint.y - linePos.y) * recipDir; if (t1 < t2) tNear = Max(t1, tNear), tFar = Min(t2, tFar); else // Swap t1 and t2. tNear = Max(t2, tNear), tFar = Min(t1, tFar); if (tNear > tFar) return false; // Box is missed since we "exit" before entering it. } else if (linePos.y < minPoint.y || linePos.y > maxPoint.y) return false; // The ray can't possibly enter the box, abort. if (!EqualAbs(lineDir.z, 0.f)) // ray is parallel to plane in question { float recipDir = RecipFast(lineDir.z); float t1 = (minPoint.z - linePos.z) * recipDir; float t2 = (maxPoint.z - linePos.z) * recipDir; if (t1 < t2) tNear = Max(t1, tNear), tFar = Min(t2, tFar); else // Swap t1 and t2. tNear = Max(t2, tNear), tFar = Min(t1, tFar); } else if (linePos.z < minPoint.z || linePos.z > maxPoint.z) return false; // The ray can't possibly enter the box, abort. return tNear <= tFar; }
void CInterceptHandler::Update(bool forced) { if (((gs->frameNum % UNIT_SLOWUPDATE_RATE) != 0) && !forced) return; std::list<CWeapon*>::iterator wit; std::map<int, CWeaponProjectile*>::const_iterator pit; for (wit = interceptors.begin(); wit != interceptors.end(); ++wit) { CWeapon* w = *wit; const WeaponDef* wDef = w->weaponDef; const CUnit* wOwner = w->owner; // const float3& wOwnerPos = wOwner->pos; const float3& wPos = w->weaponPos; for (pit = interceptables.begin(); pit != interceptables.end(); ++pit) { CWeaponProjectile* p = pit->second; const WeaponDef* pDef = p->weaponDef; if ((pDef->targetable & wDef->interceptor) == 0) continue; if (w->incomingProjectiles.find(p->id) != w->incomingProjectiles.end()) continue; const CUnit* pOwner = p->owner(); const int pAllyTeam = (pOwner != NULL)? pOwner->allyteam: -1; if (pAllyTeam != -1 && teamHandler->Ally(wOwner->allyteam, pAllyTeam)) continue; // there are four cases when an interceptor <w> should fire at a projectile <p>: // 1. p's target position inside w's interception circle (w's owner can move!) // 2. p's current position inside w's interception circle // 3. p's projected impact position inside w's interception circle // 4. p's trajectory intersects w's interception circle // // these checks all need to be evaluated periodically, not just // when a projectile is created and handed to AddInterceptTarget const float interceptDist = (w->weaponPos - p->pos).Length(); const float impactDist = ground->LineGroundCol(p->pos, p->pos + p->dir * interceptDist); const float3& pFlightPos = p->pos; const float3& pImpactPos = p->pos + p->dir * impactDist; const float3& pTargetPos = p->targetPos; if ((pTargetPos - wPos).SqLength2D() < Square(wDef->coverageRange)) { w->AddDeathDependence(p, CObject::DEPENDENCE_INTERCEPT); w->incomingProjectiles[p->id] = p; continue; // 1 } if (wDef->interceptor == 1) { // <w> is just a static interceptor and fires only at projectiles // TARGETED within its current interception area; any projectiles // CROSSING its interception area are fired at only if interceptor // is >= 2 continue; } if ((pFlightPos - wPos).SqLength2D() < Square(wDef->coverageRange)) { w->AddDeathDependence(p, CObject::DEPENDENCE_INTERCEPT); w->incomingProjectiles[p->id] = p; continue; // 2 } if ((pImpactPos - wPos).SqLength2D() < Square(wDef->coverageRange)) { const float3 pTargetDir = (pTargetPos - pFlightPos).SafeNormalize(); const float3 pImpactDir = (pImpactPos - pFlightPos).SafeNormalize(); // the projected impact position can briefly shift into the covered // area during transition from vertical to horizontal flight, so we // perform an extra test (NOTE: assumes non-parabolic trajectory) if (pTargetDir.dot(pImpactDir) >= 0.999f) { w->AddDeathDependence(p, CObject::DEPENDENCE_INTERCEPT); w->incomingProjectiles[p->id] = p; continue; // 3 } } const float3 pCurSeparationVec = wPos - pFlightPos; const float pMinSeparationDist = std::max(pCurSeparationVec.dot(p->dir), 0.0f); const float3 pMinSeparationPos = pFlightPos + (p->dir * pMinSeparationDist); const float3 pMinSeparationVec = wPos - pMinSeparationPos; if (pMinSeparationVec.SqLength() < Square(wDef->coverageRange)) { w->AddDeathDependence(p, CObject::DEPENDENCE_INTERCEPT); w->incomingProjectiles[p->id] = p; continue; // 4 } } } }
/** * Stores data and does some top-administration */ IPath::SearchResult CPathEstimator::GetPath( const MoveData& moveData, float3 start, const CPathFinderDef& peDef, Path& path, unsigned int maxSearchedBlocks, bool synced ) { start.CheckInBounds(); // clear the path path.path.clear(); path.pathCost = PATHCOST_INFINITY; // initial calculations maxBlocksToBeSearched = std::min(maxSearchedBlocks, MAX_SEARCHED_BLOCKS - 8U); startBlock.x = (int)(start.x / BLOCK_PIXEL_SIZE); startBlock.y = (int)(start.z / BLOCK_PIXEL_SIZE); startBlocknr = startBlock.y * nbrOfBlocksX + startBlock.x; int2 goalBlock; goalBlock.x = peDef.goalSquareX / BLOCK_SIZE; goalBlock.y = peDef.goalSquareZ / BLOCK_SIZE; if (synced) { CPathCache::CacheItem* ci = pathCache->GetCachedPath(startBlock, goalBlock, peDef.sqGoalRadius, moveData.pathType); if (ci) { // use a cached path if we have one (NOTE: only when in synced context) path = ci->path; return ci->result; } } // oterhwise search SearchResult result = InitSearch(moveData, peDef); // if search successful, generate new path if (result == Ok || result == GoalOutOfRange) { FinishSearch(moveData, path); if (synced) { // add succesful paths to the cache (NOTE: only when in synced context) pathCache->AddPath(&path, result, startBlock, goalBlock, peDef.sqGoalRadius, moveData.pathType); } if (PATHDEBUG) { LogObject() << "PE: Search completed.\n"; LogObject() << "Tested blocks: " << testedBlocks << "\n"; LogObject() << "Open blocks: " << openBlockBufferIndex << "\n"; LogObject() << "Path length: " << (int)(path.path.size()) << "\n"; LogObject() << "Path cost: " << path.pathCost << "\n"; } } else { if (PATHDEBUG) { LogObject() << "PE: Search failed!\n"; LogObject() << "Tested blocks: " << testedBlocks << "\n"; LogObject() << "Open blocks: " << openBlockBufferIndex << "\n"; } } return result; }
RenderDecal::RenderDecal(TexturePtr const & normal_tex, TexturePtr const & diffuse_tex, float3 const & diffuse_clr, TexturePtr const & specular_tex, float3 const & specular_level, float shininess) : RenderableHelper(L"Decal") { this->BindDeferredEffect(SyncLoadRenderEffect("Decal.fxml")); gbuffer_alpha_test_rt0_tech_ = deferred_effect_->TechniqueByName("DecalGBufferAlphaTestRT0Tech"); gbuffer_alpha_test_rt1_tech_ = deferred_effect_->TechniqueByName("DecalGBufferAlphaTestRT1Tech"); gbuffer_alpha_test_mrt_tech_ = deferred_effect_->TechniqueByName("DecalGBufferAlphaTestMRTTech"); technique_ = gbuffer_alpha_test_rt0_tech_; pos_aabb_ = AABBox(float3(-1, -1, -1), float3(1, 1, 1)); tc_aabb_ = AABBox(float3(0, 0, 0), float3(1, 1, 0)); float3 xyzs[] = { pos_aabb_.Corner(0), pos_aabb_.Corner(1), pos_aabb_.Corner(2), pos_aabb_.Corner(3), pos_aabb_.Corner(4), pos_aabb_.Corner(5), pos_aabb_.Corner(6), pos_aabb_.Corner(7) }; uint16_t indices[] = { 0, 2, 3, 3, 1, 0, 5, 7, 6, 6, 4, 5, 4, 0, 1, 1, 5, 4, 4, 6, 2, 2, 0, 4, 2, 6, 7, 7, 3, 2, 1, 3, 7, 7, 5, 1 }; RenderFactory& rf = Context::Instance().RenderFactoryInstance(); rl_ = rf.MakeRenderLayout(); rl_->TopologyType(RenderLayout::TT_TriangleList); ElementInitData init_data; init_data.row_pitch = sizeof(xyzs); init_data.slice_pitch = 0; init_data.data = xyzs; GraphicsBufferPtr vb = rf.MakeVertexBuffer(BU_Static, EAH_GPU_Read | EAH_Immutable, &init_data); rl_->BindVertexStream(vb, make_tuple(vertex_element(VEU_Position, 0, EF_BGR32F))); init_data.row_pitch = sizeof(indices); init_data.slice_pitch = 0; init_data.data = indices; GraphicsBufferPtr ib = rf.MakeIndexBuffer(BU_Static, EAH_GPU_Read | EAH_Immutable, &init_data); rl_->BindIndexStream(ib, EF_R16UI); model_mat_ = float4x4::Identity(); effect_attrs_ |= EA_AlphaTest; inv_mv_ep_ = technique_->Effect().ParameterByName("inv_mv"); g_buffer_rt0_tex_param_ = deferred_effect_->ParameterByName("g_buffer_rt0_tex"); normal_tex_ = normal_tex; diffuse_tex_ = diffuse_tex; diffuse_clr_ = diffuse_clr; specular_tex_ = specular_tex; specular_level_ = specular_level.x(); shininess_ = shininess; }
float3 CDefenseMatrix::GetDefensePos(const UnitDef* def, float3 builderpos) { ai->ut->UpdateChokePointArray(); int f3multiplier = 8 * THREATRES; int Range = int(ai->ut->GetMaxRange(def) / f3multiplier); int bestspotx = 0; int bestspoty = 0; float averagemapsize = sqrt(float(ai->pather->PathMapXSize * ai->pather->PathMapYSize)) * f3multiplier; float bestscore_fast = 0.0f; int bestspotx_fast = 0; int bestspoty_fast = 0; ai->math->TimerStart(); spotFinder->SetRadius(Range); float* sumMap = spotFinder->GetSumMap(); // hack to find a good start { int x = (int) (builderpos.x / f3multiplier); int y = (int) (builderpos.z / f3multiplier); float fastSumMap = sumMap[y * ai->pather->PathMapXSize + x]; float3 spotpos = float3(x * f3multiplier, 0, y * f3multiplier); float myscore = fastSumMap / (builderpos.distance2D(spotpos) + averagemapsize / 8) * ((ai->pather->HeightMap[y * ai->pather->PathMapXSize + x] + 200) / (ai->pather->AverageHeight + 10)) / (ai->tm->ThreatAtThisPoint(spotpos) + 0.01); bestscore_fast = myscore; bestspotx_fast = x; bestspoty_fast = y; } int skipCount = 0; int testCount = 0; for (int x = 0; x < ai->pather->PathMapXSize / CACHEFACTOR; x++) { for (int y = 0; y < ai->pather->PathMapYSize / CACHEFACTOR; y++) { // KLOOTNOTE: SOMETIMES RETURNS UNINITIALIZED CRAP? // (gdb) print cachePoint->y $2 = 219024104 // (gdb) print cachePoint->x $3 = -1215908928 CachePoint* cachePoint = spotFinder->GetBestCachePoint(x, y); if (!cachePoint) { return ZeroVector; } float bestScoreInThisBox = cachePoint->maxValueInBox; // guess that this point is as good as posible // make best posible build spot (nearest to builder) float bestX = builderpos.x / f3multiplier; float bestY = builderpos.z / f3multiplier; if (bestX > x * CACHEFACTOR) { if (bestX > (x * CACHEFACTOR + CACHEFACTOR)) { bestX = x * CACHEFACTOR + CACHEFACTOR; } } else { bestX = x * CACHEFACTOR; } if (bestY > y * CACHEFACTOR) { if (bestY > (y * CACHEFACTOR + CACHEFACTOR)) { bestY = y * CACHEFACTOR + CACHEFACTOR; } } else { bestY = y * CACHEFACTOR; } float3 bestPosibleSpotpos = float3(bestX * f3multiplier, 0, bestY * f3multiplier); // this must be guessed, set it to the best possible (slow) float bestThreatAtThisPoint = 0.01 + ai->tm->GetAverageThreat() - 1; float bestDistance = builderpos.distance2D(bestPosibleSpotpos); float bestHeight = ai->pather->HeightMap[cachePoint->y * ai->pather->PathMapXSize + cachePoint->x] + 200; float bestPosibleMyScore = bestScoreInThisBox / (bestDistance + averagemapsize / 4) * (bestHeight + 200) / bestThreatAtThisPoint; // have a best posible score for all points inside the size of the cache box // if this is better than the current known best, test if any point inside the box is better if (bestPosibleMyScore > bestscore_fast) { testCount++; // must test all the points inside this box for (int sx = x * CACHEFACTOR; sx < ai->pather->PathMapXSize && sx < (x * CACHEFACTOR + CACHEFACTOR); sx++) { for (int sy = y * CACHEFACTOR; sy < ai->pather->PathMapYSize && sy < (y * CACHEFACTOR + CACHEFACTOR); sy++) { float fastSumMap = sumMap[sy * ai->pather->PathMapXSize + sx]; float3 spotpos = float3(sx * f3multiplier, 0, sy * f3multiplier); float myscore = fastSumMap / (builderpos.distance2D(spotpos) + averagemapsize / 4) * (ai->pather->HeightMap[sy * ai->pather->PathMapXSize + sx]+200) / (ai->tm->ThreatAtThisPoint(spotpos) + 0.01); // THIS COULD BE REALLY SLOW! if (myscore > bestscore_fast && BuildMaskArray[sy * ai->pather->PathMapXSize + sx] == 0 && ai->cb->CanBuildAt(def, spotpos)) { bestscore_fast = myscore; bestspotx_fast = sx; bestspoty_fast = sy; } } } } else { // skip box skipCount++; } } } bestspotx = bestspotx_fast; bestspoty = bestspoty_fast; return float3(bestspotx * f3multiplier, 0, bestspoty * f3multiplier); }
void CLargeBeamLaserProjectile::Draw() { inArray = true; const float3 cameraDir = (pos - camera->pos).SafeANormalize(); // beam's coor-system; degenerate if targetPos == startPos const float3 zdir = (targetPos - startpos).SafeANormalize(); const float3 xdir = (cameraDir.cross(zdir)).SafeANormalize(); const float3 ydir = (cameraDir.cross(xdir)); float3 pos1 = startpos; float3 pos2 = targetPos; const float startTex = 1.0f - ((gu->modGameTime * scrollspeed) - int(gu->modGameTime * scrollspeed)); const float texSizeX = beamtex.xend - beamtex.xstart; const float beamEdgeSize = thickness; const float beamCoreSize = beamEdgeSize * corethickness; const float beamLength = (targetPos - startpos).dot(zdir); const float flareEdgeSize = thickness * flaresize; const float flareCoreSize = flareEdgeSize * corethickness; const float beamTileMinDst = tilelength * (1.0f - startTex); const float beamTileMaxDst = beamLength - tilelength; // note: beamTileMaxDst can be negative, in which case we want numBeamTiles to equal zero const float numBeamTiles = std::floor(((std::max(beamTileMinDst, beamTileMaxDst) - beamTileMinDst) / tilelength) + 0.5f); AtlasedTexture tex = beamtex; va->EnlargeArrays(64 + (8 * (int((beamTileMaxDst - beamTileMinDst) / tilelength) + 2)), 0, VA_SIZE_TC); #define WT2 weaponDef->visuals.texture2 #define WT4 weaponDef->visuals.texture4 if (beamTileMinDst > beamLength) { // beam short enough to be drawn by one polygon // draw laser start tex.xstart = beamtex.xstart + startTex * texSizeX; va->AddVertexQTC(pos1 - (xdir * beamEdgeSize), tex.xstart, tex.ystart, edgeColStart); va->AddVertexQTC(pos1 + (xdir * beamEdgeSize), tex.xstart, tex.yend, edgeColStart); va->AddVertexQTC(pos2 + (xdir * beamEdgeSize), tex.xend, tex.yend, edgeColStart); va->AddVertexQTC(pos2 - (xdir * beamEdgeSize), tex.xend, tex.ystart, edgeColStart); va->AddVertexQTC(pos1 - (xdir * beamCoreSize), tex.xstart, tex.ystart, coreColStart); va->AddVertexQTC(pos1 + (xdir * beamCoreSize), tex.xstart, tex.yend, coreColStart); va->AddVertexQTC(pos2 + (xdir * beamCoreSize), tex.xend, tex.yend, coreColStart); va->AddVertexQTC(pos2 - (xdir * beamCoreSize), tex.xend, tex.ystart, coreColStart); } else { // beam longer than one polygon pos2 = pos1 + zdir * beamTileMinDst; // draw laser start tex.xstart = beamtex.xstart + startTex * texSizeX; va->AddVertexQTC(pos1 - (xdir * beamEdgeSize), tex.xstart, tex.ystart, edgeColStart); va->AddVertexQTC(pos1 + (xdir * beamEdgeSize), tex.xstart, tex.yend, edgeColStart); va->AddVertexQTC(pos2 + (xdir * beamEdgeSize), tex.xend, tex.yend, edgeColStart); va->AddVertexQTC(pos2 - (xdir * beamEdgeSize), tex.xend, tex.ystart, edgeColStart); va->AddVertexQTC(pos1 - (xdir * beamCoreSize), tex.xstart, tex.ystart, coreColStart); va->AddVertexQTC(pos1 + (xdir * beamCoreSize), tex.xstart, tex.yend, coreColStart); va->AddVertexQTC(pos2 + (xdir * beamCoreSize), tex.xend, tex.yend, coreColStart); va->AddVertexQTC(pos2 - (xdir * beamCoreSize), tex.xend, tex.ystart, coreColStart); // draw continous beam tex.xstart = beamtex.xstart; for (float i = beamTileMinDst; i < beamTileMaxDst; i += tilelength) { //! CAUTION: loop count must match EnlargeArrays above pos1 = startpos + zdir * i; pos2 = startpos + zdir * (i + tilelength); va->AddVertexQTC(pos1 - (xdir * beamEdgeSize), tex.xstart, tex.ystart, edgeColStart); va->AddVertexQTC(pos1 + (xdir * beamEdgeSize), tex.xstart, tex.yend, edgeColStart); va->AddVertexQTC(pos2 + (xdir * beamEdgeSize), tex.xend, tex.yend, edgeColStart); va->AddVertexQTC(pos2 - (xdir * beamEdgeSize), tex.xend, tex.ystart, edgeColStart); va->AddVertexQTC(pos1 - (xdir * beamCoreSize), tex.xstart, tex.ystart, coreColStart); va->AddVertexQTC(pos1 + (xdir * beamCoreSize), tex.xstart, tex.yend, coreColStart); va->AddVertexQTC(pos2 + (xdir * beamCoreSize), tex.xend, tex.yend, coreColStart); va->AddVertexQTC(pos2 - (xdir * beamCoreSize), tex.xend, tex.ystart, coreColStart); } // draw laser end pos1 = startpos + zdir * (beamTileMinDst + numBeamTiles * tilelength); pos2 = targetPos; tex.xend = tex.xstart + (pos1.distance(pos2) / tilelength) * texSizeX; va->AddVertexQTC(pos1 - (xdir * beamEdgeSize), tex.xstart, tex.ystart, edgeColStart); va->AddVertexQTC(pos1 + (xdir * beamEdgeSize), tex.xstart, tex.yend, edgeColStart); va->AddVertexQTC(pos2 + (xdir * beamEdgeSize), tex.xend, tex.yend, edgeColStart); va->AddVertexQTC(pos2 - (xdir * beamEdgeSize), tex.xend, tex.ystart, edgeColStart); va->AddVertexQTC(pos1 - (xdir * beamCoreSize), tex.xstart, tex.ystart, coreColStart); va->AddVertexQTC(pos1 + (xdir * beamCoreSize), tex.xstart, tex.yend, coreColStart); va->AddVertexQTC(pos2 + (xdir * beamCoreSize), tex.xend, tex.yend, coreColStart); va->AddVertexQTC(pos2 - (xdir * beamCoreSize), tex.xend, tex.ystart, coreColStart); } va->AddVertexQTC(pos2 - (xdir * beamEdgeSize), WT2->xstart, WT2->ystart, edgeColStart); va->AddVertexQTC(pos2 + (xdir * beamEdgeSize), WT2->xstart, WT2->yend, edgeColStart); va->AddVertexQTC(pos2 + (xdir * beamEdgeSize) + (ydir * beamEdgeSize), WT2->xend, WT2->yend, edgeColStart); va->AddVertexQTC(pos2 - (xdir * beamEdgeSize) + (ydir * beamEdgeSize), WT2->xend, WT2->ystart, edgeColStart); va->AddVertexQTC(pos2 - (xdir * beamCoreSize), WT2->xstart, WT2->ystart, coreColStart); va->AddVertexQTC(pos2 + (xdir * beamCoreSize), WT2->xstart, WT2->yend, coreColStart); va->AddVertexQTC(pos2 + (xdir * beamCoreSize) + (ydir * beamCoreSize), WT2->xend, WT2->yend, coreColStart); va->AddVertexQTC(pos2 - (xdir * beamCoreSize) + (ydir * beamCoreSize), WT2->xend, WT2->ystart, coreColStart); float pulseStartTime = (gu->modGameTime * pulseSpeed) - int(gu->modGameTime * pulseSpeed); float muzzleEdgeSize = thickness * flaresize * pulseStartTime; float muzzleCoreSize = muzzleEdgeSize * 0.6f; unsigned char coreColor[4] = {0, 0, 0, 1}; unsigned char edgeColor[4] = {0, 0, 0, 1}; for (int i = 0; i < 3; i++) { coreColor[i] = int(coreColStart[i] * (1.0f - pulseStartTime)); edgeColor[i] = int(edgeColStart[i] * (1.0f - pulseStartTime)); } { // draw muzzleflare pos1 = startpos - zdir * (thickness * flaresize) * 0.02f; va->AddVertexQTC(pos1 + (ydir * muzzleEdgeSize), sidetex.xstart, sidetex.ystart, edgeColor); va->AddVertexQTC(pos1 + (ydir * muzzleEdgeSize) + (zdir * muzzleEdgeSize), sidetex.xend, sidetex.ystart, edgeColor); va->AddVertexQTC(pos1 - (ydir * muzzleEdgeSize) + (zdir * muzzleEdgeSize), sidetex.xend, sidetex.yend, edgeColor); va->AddVertexQTC(pos1 - (ydir * muzzleEdgeSize), sidetex.xstart, sidetex.yend, edgeColor); va->AddVertexQTC(pos1 + (ydir * muzzleCoreSize), sidetex.xstart, sidetex.ystart, coreColor); va->AddVertexQTC(pos1 + (ydir * muzzleCoreSize) + (zdir * muzzleCoreSize), sidetex.xend, sidetex.ystart, coreColor); va->AddVertexQTC(pos1 - (ydir * muzzleCoreSize) + (zdir * muzzleCoreSize), sidetex.xend, sidetex.yend, coreColor); va->AddVertexQTC(pos1 - (ydir * muzzleCoreSize), sidetex.xstart, sidetex.yend, coreColor); pulseStartTime += 0.5f; pulseStartTime -= (1.0f * (pulseStartTime > 1.0f)); for (int i = 0; i < 3; i++) { coreColor[i] = int(coreColStart[i] * (1.0f - pulseStartTime)); edgeColor[i] = int(edgeColStart[i] * (1.0f - pulseStartTime)); } muzzleEdgeSize = thickness * flaresize * pulseStartTime; va->AddVertexQTC(pos1 + (ydir * muzzleEdgeSize), sidetex.xstart, sidetex.ystart, edgeColor); va->AddVertexQTC(pos1 + (ydir * muzzleEdgeSize) + (zdir * muzzleEdgeSize), sidetex.xend, sidetex.ystart, edgeColor); va->AddVertexQTC(pos1 - (ydir * muzzleEdgeSize) + (zdir * muzzleEdgeSize), sidetex.xend, sidetex.yend, edgeColor); va->AddVertexQTC(pos1 - (ydir * muzzleEdgeSize), sidetex.xstart, sidetex.yend, edgeColor); muzzleCoreSize = muzzleEdgeSize * 0.6f; va->AddVertexQTC(pos1 + (ydir * muzzleCoreSize), sidetex.xstart, sidetex.ystart, coreColor); va->AddVertexQTC(pos1 + (ydir * muzzleCoreSize) + (zdir * muzzleCoreSize), sidetex.xend, sidetex.ystart, coreColor); va->AddVertexQTC(pos1 - (ydir * muzzleCoreSize) + (zdir * muzzleCoreSize), sidetex.xend, sidetex.yend, coreColor); va->AddVertexQTC(pos1 - (ydir * muzzleCoreSize), sidetex.xstart, sidetex.yend, coreColor); } { // draw flare (moved slightly along the camera direction) pos1 = startpos - (camera->forward * 3.0f); va->AddVertexQTC(pos1 - (camera->right * flareEdgeSize) - (camera->up * flareEdgeSize), WT4->xstart, WT4->ystart, edgeColStart); va->AddVertexQTC(pos1 + (camera->right * flareEdgeSize) - (camera->up * flareEdgeSize), WT4->xend, WT4->ystart, edgeColStart); va->AddVertexQTC(pos1 + (camera->right * flareEdgeSize) + (camera->up * flareEdgeSize), WT4->xend, WT4->yend, edgeColStart); va->AddVertexQTC(pos1 - (camera->right * flareEdgeSize) + (camera->up * flareEdgeSize), WT4->xstart, WT4->yend, edgeColStart); va->AddVertexQTC(pos1 - (camera->right * flareCoreSize) - (camera->up * flareCoreSize), WT4->xstart, WT4->ystart, coreColStart); va->AddVertexQTC(pos1 + (camera->right * flareCoreSize) - (camera->up * flareCoreSize), WT4->xend, WT4->ystart, coreColStart); va->AddVertexQTC(pos1 + (camera->right * flareCoreSize) + (camera->up * flareCoreSize), WT4->xend, WT4->yend, coreColStart); va->AddVertexQTC(pos1 - (camera->right * flareCoreSize) + (camera->up * flareCoreSize), WT4->xstart, WT4->yend, coreColStart); } #undef WT4 #undef WT2 }
/* Removes and return the next waypoint in the multipath corresponding to given id. */ float3 CPathManager::NextWaypoint(unsigned int pathId, float3 callerPos, float minDistance, int numRetries, int ownerId, bool synced) const { SCOPED_TIMER("PFS"); // 0 indicates a no-path id if (pathId == 0) return float3(-1.0f, -1.0f, -1.0f); if (numRetries > 4) return float3(-1.0f, -1.0f, -1.0f); //Find corresponding multipath. std::map<unsigned int, MultiPath*>::const_iterator pi = pathMap.find(pathId); if (pi == pathMap.end()) return float3(-1.0f, -1.0f, -1.0f); MultiPath* multiPath = pi->second; if (callerPos == ZeroVector) { if (!multiPath->detailedPath.path.empty()) callerPos = multiPath->detailedPath.path.back(); } // check if detailed path needs bettering if (!multiPath->estimatedPath.path.empty() && (multiPath->estimatedPath.path.back().SqDistance2D(callerPos) < Square(MIN_DETAILED_DISTANCE * SQUARE_SIZE) || multiPath->detailedPath.path.size() <= 2)) { if (!multiPath->estimatedPath2.path.empty() && // if so, check if estimated path also needs bettering (multiPath->estimatedPath2.path.back().SqDistance2D(callerPos) < Square(MIN_ESTIMATE_DISTANCE * SQUARE_SIZE) || multiPath->estimatedPath.path.size() <= 2)) { Estimate2ToEstimate(*multiPath, callerPos, ownerId, synced); } if (multiPath->caller) { multiPath->caller->UnBlock(); } EstimateToDetailed(*multiPath, callerPos, ownerId); if (multiPath->caller) { multiPath->caller->Block(); } } float3 waypoint; do { // get the next waypoint from the high-res path // // if this is not possible, then either we are // at the goal OR the path could not reach all // the way to it (ie. a GoalOutOfRange result) if (multiPath->detailedPath.path.empty()) { if (multiPath->estimatedPath2.path.empty() && multiPath->estimatedPath.path.empty()) { if (multiPath->searchResult == IPath::Ok) { return multiPath->finalGoal; } else { return float3(-1.0f, -1.0f, -1.0f); } } else { return NextWaypoint(pathId, callerPos, minDistance, numRetries + 1, ownerId, synced); } } else { waypoint = multiPath->detailedPath.path.back(); multiPath->detailedPath.path.pop_back(); } } while (callerPos.SqDistance2D(waypoint) < Square(minDistance) && waypoint != multiPath->detailedPath.pathGoal); return waypoint; }
float length(const float3 &vec) { return vec.length(); }
float3 AABB::ClosestPoint(const float3 &targetPoint) const { return targetPoint.Clamp(minPoint, maxPoint); }
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; } }
Plane::Plane(const Ray &ray, const float3 &normal) { float3 perpNormal = normal - normal.ProjectToNorm(ray.dir); Set(ray.pos, perpNormal.Normalized()); }
/* Removes and return the next waypoint in the multipath corresponding to given id. */ float3 CPathManager::NextWaypoint(unsigned int pathId, float3 callerPos, float minDistance, int numRetries) { #ifdef PROFILE_TIME LARGE_INTEGER starttime; QueryPerformanceCounter(&starttime); #endif //0 indicate a no-path id. if(pathId == 0) return float3(-1,-1,-1); if(numRetries>4) return float3(-1,-1,-1); //Find corresponding multipath. map<unsigned int, MultiPath*>::iterator pi = pathMap.find(pathId); if(pi == pathMap.end()) return float3(-1,-1,-1); MultiPath* multiPath = pi->second; if(callerPos==ZeroVector){ if(!multiPath->detailedPath.path.empty()) callerPos=multiPath->detailedPath.path.back(); } //check if detailed path need bettering if(!multiPath->estimatedPath.path.empty() && (multiPath->estimatedPath.path.back().distance2D(callerPos) < MIN_DETAILED_DISTANCE * SQUARE_SIZE || multiPath->detailedPath.path.size() <= 2)){ if(!multiPath->estimatedPath2.path.empty() //if so check if estimated path also need bettering && (multiPath->estimatedPath2.path.back().distance2D(callerPos) < MIN_ESTIMATE_DISTANCE * SQUARE_SIZE || multiPath->estimatedPath.path.size() <= 2)){ Estimate2ToEstimate(*multiPath, callerPos); } if(multiPath->caller) multiPath->caller->UnBlock(); EstimateToDetailed(*multiPath, callerPos); if(multiPath->caller) multiPath->caller->Block(); } //Repeat until a waypoint distant enought are found. float3 waypoint; do { //Get next waypoint. if(multiPath->detailedPath.path.empty()) { if(multiPath->estimatedPath2.path.empty() && multiPath->estimatedPath.path.empty()) return multiPath->finalGoal; else return NextWaypoint(pathId,callerPos,minDistance,numRetries+1); } else { waypoint = multiPath->detailedPath.path.back(); multiPath->detailedPath.path.pop_back(); } } while(callerPos.distance2D(waypoint) < minDistance && waypoint != multiPath->detailedPath.pathGoal); //Return the result. #ifdef PROFILE_TIME LARGE_INTEGER stop; QueryPerformanceCounter(&stop); profiler.AddTime("AI:PFS",stop.QuadPart - starttime.QuadPart); #endif return waypoint; }
Plane::Plane(const LineSegment &lineSegment, const float3 &normal) { float3 perpNormal = normal - normal.ProjectTo(lineSegment.b - lineSegment.a); Set(lineSegment.a, perpNormal.Normalized()); }
float CAICallback::GetPathLength(float3 start, float3 end, int pathType, float goalRadius) { const int pathID = InitPath(start, end, pathType, goalRadius); float pathLen = -1.0f; if (pathID == 0) { return pathLen; } std::vector<float3> points; std::vector<int> lengths; pathManager->GetPathWayPoints(pathID, points, lengths); if (points.empty()) { return 0.0f; } // distance to first intermediate node pathLen = start.distance(points[0]); // we don't care which path segment has // what resolution, just lump all points // together for (size_t i = 1; i < points.size(); i++) { pathLen += points[i].distance(points[i - 1]); } /* // this method does not work without a path-owner // TODO: add an alternate GPL() callback for this? bool haveNextWP = true; float3 currWP = start; float3 nextWP = start; while (haveNextWP) { nextWP = GetNextWaypoint(pathID); if (nextWP.y == -2) { // next path node not yet known continue; } if (nextWP.y == -1) { if (nextWP.x >= 0.0f && nextWP.z >= 0.0f) { // end of path (nextWP == end) pathLen += (nextWP - currWP).Length2D(); } else { // invalid path pathLen = -1.0f; } haveNextWP = false; } else { pathLen += (nextWP - currWP).Length2D(); currWP = nextWP; } } */ FreePath(pathID); return pathLen; }