CFireProjectile::CFireProjectile(const float3& pos,const float3& speed,CUnit* owner,int emitTtl,float emitRadius,int particleTtl,float particleSize) : CProjectile(pos,speed,owner), ttl(emitTtl), emitPos(pos), emitRadius(emitRadius), particleTime(particleTtl), particleSize(particleSize) { drawRadius=emitRadius+particleTime*speed.Length(); checkCol=false; this->pos.y+=particleTime*speed.Length()*0.5; ageSpeed=1.0/particleTime; alwaysVisible=true; castShadow=true; }
static float GetCamDistOfGrassBlock(const int x, const int y, const bool square = false) { float3 quadCenter = float3(x, 0.f, y) * gSSsq; quadCenter.y = CGround::GetHeightReal(quadCenter.x, quadCenter.z, false); const float3 dif = camera->GetPos() - quadCenter; return (square) ? dif.SqLength() : dif.Length(); }
/** For reference, see http://realtimecollisiondetection.net/blog/?p=20 . */ Sphere Sphere::FitThroughPoints(const float3 &a, const float3 &b, const float3 &c) { Sphere sphere; float3 ab = b-a; float3 ac = c-a; float s, t; bool success = FitSphereThroughPoints(ab, ac, s, t); if (!success) { LOGW("Sphere::FitThroughPoints(a,b,c) failed! The three input points are collinear!"); sphere.SetDegenerate(); return sphere; } const float3 p = s*ab + t*ac; // In our translated coordinate space, the origin lies on the sphere, so the distance of p from origin // gives the radius of the sphere. sphere.r = p.Length(); // Translate back to original coordinate space. sphere.pos = a + p; return sphere; }
CTorpedoProjectile::CTorpedoProjectile( const float3& pos, const float3& speed, CUnit* owner, float areaOfEffect, float maxSpeed, float tracking, int ttl, CUnit* target, const WeaponDef* weaponDef) : CWeaponProjectile(pos, speed, owner, target, ZeroVector, weaponDef, NULL, ttl), tracking(tracking), maxSpeed(maxSpeed), areaOfEffect(areaOfEffect), target(target), nextBubble(4) { projectileType = WEAPON_TORPEDO_PROJECTILE; curSpeed = speed.Length(); dir = speed / curSpeed; if (target) { AddDeathDependence(target); } SetRadius(0.0f); drawRadius = maxSpeed * 8; // const float3 camDir = (pos - camera->pos).Normalize(); texx = projectileDrawer->torpedotex->xstart - (projectileDrawer->torpedotex->xend - projectileDrawer->torpedotex->xstart) * 0.5f; texy = projectileDrawer->torpedotex->ystart - (projectileDrawer->torpedotex->yend - projectileDrawer->torpedotex->ystart) * 0.5f; #ifdef TRACE_SYNC tracefile << "New projectile: "; tracefile << pos.x << " " << pos.y << " " << pos.z << " " << speed.x << " " << speed.y << " " << speed.z << "\n"; #endif cegID = gCEG->Load(explGenHandler, cegTag); }
CLaserProjectile::CLaserProjectile(const float3& pos, const float3& speed, CUnit* owner, float length, const float3& color, const float3& color2, float intensity, const WeaponDef *weaponDef, int ttl GML_PARG_C) : CWeaponProjectile(pos,speed,owner,0,ZeroVector,weaponDef,0, true, ttl GML_PARG_P), color(color), color2(color2), length(length), curLength(0), stayTime(0), intensity(intensity), intensityFalloff(weaponDef?intensity*weaponDef->falloffRate:0) { dir=speed; dir.Normalize(); speedf=speed.Length(); if (weaponDef) SetRadius(weaponDef->collisionSize); drawRadius=length; if (weaponDef)midtexx = weaponDef->visuals.texture2->xstart + (weaponDef->visuals.texture2->xend-weaponDef->visuals.texture2->xstart)*0.5f; #ifdef TRACE_SYNC tracefile << "New laser: "; tracefile << pos.x << " " << pos.y << " " << pos.z << " " << speed.x << " " << speed.y << " " << speed.z << "\n"; #endif if (cegTag.size() > 0) { ceg.Load(explGenHandler, cegTag); } }
void CGameHelper::DoExplosionDamage( CFeature* feature, const float3& expPos, float expRad, const DamageArray& damages, const int weaponDefID ) { const CollisionVolume* cv = feature->collisionVolume; if (cv) { const float3 dif = (feature->midPos + cv->GetOffsets()) - expPos; float expDist = std::max(dif.Length(), 0.1f); float expMod = (expRad - expDist) / expRad; float dmgScale = (damages.GetDefaultDamage() + damages.impulseBoost); // always do some damage with explosive stuff // (DDM wreckage etc. is too big to normally // be damaged otherwise, even by BB shells) // NOTE: this will also be only approximate // for non-spherical volumes if ((expRad > SQUARE_SIZE) && (expDist < (cv->GetBoundingRadius() * 1.1f)) && (expMod < 0.1f)) { expMod = 0.1f; } if (expMod > 0.0f) { const DamageArray modDamages = damages * expMod; const float3& modImpulse = dif * (damages.impulseFactor * expMod / expDist * dmgScale); feature->DoDamage(modDamages, modImpulse, NULL, weaponDefID); } } }
static float GetCamDistOfGrassBlock(const int x, const int y, const bool square = false) { const float qx = x * gSSsq; const float qz = y * gSSsq; const float3 mid = float3(qx, CGround::GetHeightReal(qx, qz, false), qz); const float3 dif = camera->GetPos() - mid; return (square) ? dif.SqLength() : dif.Length(); }
CMissileProjectile::CMissileProjectile(const float3& pos,const float3& speed,CUnit* owner,const DamageArray& damages,float areaOfEffect,float maxSpeed, int ttl,CUnit* target, WeaponDef *weaponDef,float3 targetPos) : CWeaponProjectile(pos,speed,owner,target,ZeroVector,weaponDef,0), damages(damages), ttl(ttl), maxSpeed(maxSpeed), target(target), dir(speed), oldSmoke(pos), age(0), drawTrail(true), numParts(0), areaOfEffect(areaOfEffect), decoyTarget(0), targPos(targetPos), wobbleTime(1), wobbleDir(0,0,0), wobbleDif(0,0,0), isWobbling(weaponDef->wobble>0), extraHeightTime(0) { curSpeed=speed.Length(); dir.Normalize(); oldDir=dir; if(target) AddDeathDependence(target); SetRadius(0.0); if(!weaponDef->visuals.modelName.empty()){ S3DOModel* model = modelParser->Load3DO(string("objects3d/")+weaponDef->visuals.modelName,1,0); if(model){ SetRadius(model->radius); } } drawRadius=radius+maxSpeed*8; ENTER_MIXED; float3 camDir=(pos-camera->pos).Normalize(); if(camera->pos.distance(pos)*0.2+(1-fabs(camDir.dot(dir)))*3000 < 200) drawTrail=false; ENTER_SYNCED; castShadow=true; #ifdef TRACE_SYNC tracefile << "New missile: "; tracefile << pos.x << " " << pos.y << " " << pos.z << " " << speed.x << " " << speed.y << " " << speed.z << "\n"; #endif if(target) target->IncomingMissile(this); if(weaponDef->trajectoryHeight>0){ float dist=pos.distance(targPos); extraHeight=dist*weaponDef->trajectoryHeight; if(dist<maxSpeed) dist=maxSpeed; extraHeightTime=(int)(dist/*+pos.distance(targPos+UpVector*dist))*0.5*//maxSpeed); extraHeightDecay=extraHeight/extraHeightTime; } }
CFireProjectile::CFireProjectile(const float3& pos, const float3& speed, CUnit* owner, int emitTtl, float emitRadius, int particleTtl, float particleSize): //! these are synced, but neither weapon nor piece //! (only burning features create instances of them) CProjectile(pos, speed, owner, true, false, false), ttl(emitTtl), emitPos(pos), emitRadius(emitRadius), particleTime(particleTtl), particleSize(particleSize) { drawRadius = emitRadius + particleTime * speed.Length(); checkCol = false; this->pos.y += particleTime * speed.Length() * 0.5f; ageSpeed = 1.0f / particleTime; alwaysVisible = true; castShadow = true; }
CFlameProjectile::CFlameProjectile(const float3& pos,const float3& speed,const float3& spread,CUnit* owner,const DamageArray& damages, WeaponDef *weaponDef, int ttl) : CWeaponProjectile(pos,speed,owner,0,ZeroVector,weaponDef,damages,0), spread(spread), curTime(0) { invttl=1.0/ttl; SetRadius(speed.Length()*0.9); }
void COrbitController::Init(const float3& p, const float3& tar) { CCamera* cam = camera; const float l = (tar == ZeroVector)? std::max(ground->LineGroundCol(p, p + cam->forward * 1024.0f), 512.0f): (p - tar).Length(); const float3 t = (tar == ZeroVector)? (p + cam->forward * l): tar; const float3 v = (t - p); const float3 w = (v / v.Length()); // do not normalize v in-place const float d = v.Length(); const float e = RAD2DEG(acos(v.Length2D() / d)); const float r = RAD2DEG(acos(w.x)); distance = cDistance = d; elevation = cElevation = e; rotation = cRotation = (v.z > 0.0f)? 180.0f + r: 180.0f - r; cen = t; }
CStarburstProjectile::CStarburstProjectile(const float3& pos,const float3& speed,CUnit* owner,float3 targetPos,const DamageArray& damages,float areaOfEffect,float maxSpeed,float tracking, int uptime,CUnit* target, WeaponDef *weaponDef, CWeaponProjectile* interceptTarget) : CWeaponProjectile(pos,speed,owner,target,targetPos,weaponDef,damages,interceptTarget), ttl(200), maxSpeed(maxSpeed), tracking(tracking), dir(speed), oldSmoke(pos), age(0), drawTrail(true), numParts(0), doturn(true), curCallback(0), numCallback(0), missileAge(0), areaOfEffect(areaOfEffect) { this->uptime=uptime; ttl=(int)min(3000.f,uptime+weaponDef->range/maxSpeed+100); maxGoodDif=cos(tracking*0.6); curSpeed=speed.Length(); dir.Normalize(); oldSmokeDir=dir; drawRadius=maxSpeed*8; ENTER_MIXED; numCallback=new int; *numCallback=0; float3 camDir=(pos-camera->pos).Normalize(); if(camera->pos.distance(pos)*0.2+(1-fabs(camDir.dot(dir)))*3000 < 200) drawTrail=false; ENTER_SYNCED; for(int a=0;a<5;++a){ oldInfos[a]=new OldInfo; oldInfos[a]->dir=dir; oldInfos[a]->pos=pos; oldInfos[a]->speedf=curSpeed; } castShadow=true; #ifdef TRACE_SYNC tracefile << "New starburst rocket: "; tracefile << pos.x << " " << pos.y << " " << pos.z << " " << speed.x << " " << speed.y << " " << speed.z << "\n"; #endif }
int CAdvTreeDrawer::AddFallingTree(float3 pos, float3 dir, int type) { GML_STDMUTEX_LOCK(tree); // AddFallingTree FallingTree ft; ft.pos=pos; dir.y=0; float s=dir.Length(); if(s>500) return 0; ft.dir=dir/s; ft.speed=std::max(0.01f,s*0.0004f); ft.type=type; ft.fallPos=0; fallingTrees.push_back(ft); return 0; }
CLaserProjectile::CLaserProjectile( const float3& pos, const float3& speed, CUnit* owner, float length, const float3& color, const float3& color2, float intensity, const WeaponDef* weaponDef, int ttl): CWeaponProjectile(pos, speed, owner, NULL, ZeroVector, weaponDef, NULL, ttl), intensity(intensity), color(color), color2(color2), length(length), curLength(0.0f), intensityFalloff(weaponDef ? (intensity * weaponDef->falloffRate) : 0.0f), stayTime(0) { projectileType = WEAPON_LASER_PROJECTILE; speedf = speed.Length(); dir = speed / speedf; if (weaponDef) { SetRadiusAndHeight(weaponDef->collisionSize, 0.0f); midtexx = (weaponDef->visuals.texture2->xstart + (weaponDef->visuals.texture2->xend - weaponDef->visuals.texture2->xstart) * 0.5f); } drawRadius = length; #ifdef TRACE_SYNC tracefile << "New laser: "; tracefile << pos.x << " " << pos.y << " " << pos.z << " " << speed.x << " " << speed.y << " " << speed.z << "\n"; #endif cegID = gCEG->Load(explGenHandler, (weaponDef != NULL)? weaponDef->cegTag: ""); }
bool CCamera::InView(const float3 &p, float radius) { const float3 t = (p - pos); const float l = t.Length(); if (l < 50.0f) { return true; } else if (l > gu->viewRange) { return false; } if ((t.dot(rightside) > radius) || (t.dot(leftside) > radius) || (t.dot(bottom) > radius) || (t.dot(top) > radius)) { return false; } return true; }
CLaserProjectile::CLaserProjectile(const float3& pos,const float3& speed,CUnit* owner,const DamageArray& damages,float length,const float3& color,float intensity, WeaponDef *weaponDef, int ttl) : CWeaponProjectile(pos,speed,owner,0,ZeroVector,weaponDef,0), damages(damages), ttl(ttl), color(color), length(length), curLength(0), intensity(intensity), intensityFalloff(intensity*0.1) { dir=speed; dir.Normalize(); speedf=speed.Length(); SetRadius(0.5); drawRadius=length; #ifdef TRACE_SYNC tracefile << "New laser: "; tracefile << pos.x << " " << pos.y << " " << pos.z << " " << speed.x << " " << speed.y << " " << speed.z << "\n"; #endif }
CLaserProjectile::CLaserProjectile(const float3& pos,const float3& speed,CUnit* owner,const DamageArray& damages,float length,const float3& color, const float3& color2, float intensity, WeaponDef *weaponDef, int ttl) : CWeaponProjectile(pos,speed,owner,0,ZeroVector,weaponDef,damages,0), ttl(ttl), color(color), color2(color2), length(length), curLength(0), intensity(intensity), intensityFalloff(intensity*0.1) { dir=speed; dir.Normalize(); speedf=speed.Length(); SetRadius(weaponDef->collisionSize); drawRadius=length; midtexx = weaponDef->visuals.texture2->xstart + (weaponDef->visuals.texture2->xend-weaponDef->visuals.texture2->xstart)*0.5; #ifdef TRACE_SYNC tracefile << "New laser: "; tracefile << pos.x << " " << pos.y << " " << pos.z << " " << speed.x << " " << speed.y << " " << speed.z << "\n"; #endif }
/** For reference, see http://realtimecollisiondetection.net/blog/?p=20 . */ Sphere Sphere::FitThroughPoints(const float3 &a, const float3 &b, const float3 &c, const float3 &d) { Sphere sphere; float s,t,u; const float3 ab = b-a; const float3 ac = c-a; const float3 ad = d-a; bool success = FitSphereThroughPoints(ab, ac, ad, s, t, u); if (success) { const float3 center = s*ab + t*ac + u*ad; sphere.r = center.Length(); sphere.pos = a + center; } else { LOGW("Sphere::FitThroughPoints through four points failed! The points lie on the same plane!"); sphere.SetDegenerate(); } return sphere; }
CTorpedoProjectile::CTorpedoProjectile(const float3& pos,const float3& speed,CUnit* owner,const DamageArray& damages,float areaOfEffect,float maxSpeed,float tracking, int ttl,CUnit* target, WeaponDef *weaponDef) : CWeaponProjectile(pos,speed,owner,target,ZeroVector,weaponDef,0), damages(damages), ttl(ttl), maxSpeed(maxSpeed), tracking(tracking), target(target), dir(speed), areaOfEffect(areaOfEffect), nextBubble(4) { curSpeed=speed.Length(); dir.Normalize(); if(target) AddDeathDependence(target); SetRadius(0.0); drawRadius=maxSpeed*8; float3 camDir=(pos-camera->pos).Normalize(); #ifdef TRACE_SYNC tracefile << "New projectile: "; tracefile << pos.x << " " << pos.y << " " << pos.z << " " << speed.x << " " << speed.y << " " << speed.z << "\n"; #endif }
void AAirMoveType::CheckForCollision() { if (!collide) return; const SyncedFloat3& pos = owner->midPos; const SyncedFloat3& forward = owner->frontdir; const float3 midTestPos = pos + forward * 121.0f; const std::vector<CUnit*>& others = quadField->GetUnitsExact(midTestPos, 115.0f); float dist = 200.0f; if (lastColWarning) { DeleteDeathDependence(lastColWarning, DEPENDENCE_LASTCOLWARN); lastColWarning = NULL; lastColWarningType = 0; } for (CUnit* unit: others) { if (unit == owner || !unit->unitDef->canfly) { continue; } const SyncedFloat3& op = unit->midPos; const float3 dif = op - pos; const float3 forwardDif = forward * (forward.dot(dif)); if (forwardDif.SqLength() >= (dist * dist)) { continue; } const float3 ortoDif = dif - forwardDif; const float frontLength = forwardDif.Length(); // note: radii are multiplied by two const float minOrtoDif = (unit->radius + owner->radius) * 2.0f + frontLength * 0.1f + 10; if (ortoDif.SqLength() < (minOrtoDif * minOrtoDif)) { dist = frontLength; lastColWarning = const_cast<CUnit*>(unit); } } if (lastColWarning != NULL) { lastColWarningType = 2; AddDeathDependence(lastColWarning, DEPENDENCE_LASTCOLWARN); return; } for (CUnit* u: others) { if (u == owner) continue; if ((u->midPos - pos).SqLength() < (dist * dist)) { lastColWarning = u; } } if (lastColWarning != NULL) { lastColWarningType = 1; AddDeathDependence(lastColWarning, DEPENDENCE_LASTCOLWARN); } }
// problems: giving reclaim order on moving target causes commander // to walk (messing up subsequent dgun order if target still moving) // and does not take commander torso rotation time into account // void CDGunController::TrackAttackTarget(unsigned int currentFrame) { if (currentFrame - state.targetSelectionFrame == 5) { // five sim-frames have passed since selecting target, attack const UnitDef* udef = ai->cb->GetUnitDef(state.targetID); const float3 curTargetPos = ai->cb->GetUnitPos(state.targetID); // current target position const float3 commanderPos = ai->cb->GetUnitPos(commanderID); // current commander position const float3 targetDif = (commanderPos - curTargetPos); const float targetDist = targetDif.Length(); // distance to target const float3 targetVel = (curTargetPos - state.oldTargetPos); float3 targetMoveDir = targetVel; float targetMoveSpeed = 0.0f; if (targetVel != ZeroVector) { targetMoveSpeed = targetVel.Length() / 5.0f; // target speed per sim-frame during tracking interval targetMoveDir = targetVel / (targetMoveSpeed * 5.0f); // target direction of movement } const float dgunDelay = targetDist / commanderWD->projectilespeed; // sim-frames needed for dgun to reach target position const float3 leadPos = targetMoveDir * (targetMoveSpeed * dgunDelay); const float3 dgunPos = curTargetPos + leadPos; // position where target will be in <dgunDelay> frames const float maxRange = ai->cb->GetUnitMaxRange(commanderID); bool haveClearShot = true; int orderType = -1; AIHCTraceRay rayData = { commanderPos, targetDif / targetDist, // direction maxRange, commanderID, -1, 0 }; ai->cb->HandleCommand(AIHCTraceRayId, &rayData); if (rayData.hitUID != -1) { // note: still fails when allied structure is between us and enemy // can also fail if enemy is in front of allied structure and both // are within the d-gun's range haveClearShot = (ai->cb->GetUnitAllyTeam(rayData.hitUID) != ai->cb->GetMyAllyTeam()); // TODO: get DGun weapon properties & check if it can pass through // a unit, if yes then allow executing the code below if(haveClearShot) { // check if there is a unit next to hit unit on DGun path... const float3 enemyPos = ai->cb->GetUnitPos(rayData.hitUID); const float segmentLeft = maxRange - commanderPos.distance(enemyPos); if(segmentLeft > 0.0) { AIHCTraceRay rayData2 = { enemyPos, targetDif / targetDist, segmentLeft, rayData.hitUID, -1, 0 }; ai->cb->HandleCommand(AIHCTraceRayId, &rayData2); if(rayData2.hitUID != -1) { haveClearShot = (ai->cb->GetUnitAllyTeam(rayData2.hitUID) != ai->cb->GetMyAllyTeam()); } } } } // multiply by 0.9 to ensure commander does not have to walk if ((commanderPos - dgunPos).Length() < maxRange * 0.9f) { bool canDGun = (ai->cb->GetEnergy() >= DGUN_MIN_ENERGY_LEVEL) && haveClearShot && (udef != NULL && !udef->weapons.empty()); if(canDGun) { IssueOrder(dgunPos, orderType = CMD_DGUN, 0); } else { bool bDanger = ai->tm->ThreatAtThisPoint(commanderPos/*curTargetPos*/) > ai->tm->GetAverageThreat(); if(bDanger) { state.Reset(currentFrame, true); } else { if (ai->cb->GetUnitHealth(state.targetID) < ai->cb->GetUnitMaxHealth(state.targetID) * 0.5f) { IssueOrder(state.targetID, orderType = CMD_RECLAIM, 0); } else { IssueOrder(state.targetID, orderType = CMD_CAPTURE, 0); } } } if (orderType == CMD_DGUN ) { state.dgunOrderFrame = ai->cb->GetCurrentFrame(); } if (orderType == CMD_RECLAIM) { state.reclaimOrderFrame = ai->cb->GetCurrentFrame(); } if (orderType == CMD_CAPTURE) { state.captureOrderFrame = ai->cb->GetCurrentFrame(); } } else { state.Reset(currentFrame, true); } } state.Reset(currentFrame, false); }
// problems: giving reclaim order on moving target causes commander // to walk (messing up subsequent dgun order if target still moving) // and does not take commander torso rotation time into account // void CDGunController::TrackAttackTarget(unsigned int currentFrame) { if (currentFrame - state.targetSelectionFrame == 5) { // five sim-frames have passed since selecting target, attack const UnitDef* udef = ai->cb->GetUnitDef(state.targetID); const float3 curTargetPos = ai->cb->GetUnitPos(state.targetID); // current target position const float3 commanderPos = ai->cb->GetUnitPos(commanderID); // current commander position const float3 targetDif = (commanderPos - curTargetPos); const float targetDist = targetDif.Length(); // distance to target const float3 targetVel = (curTargetPos - state.oldTargetPos); float3 targetMoveDir = targetVel; float targetMoveSpeed = 0.0f; if (targetVel != ZeroVector) { targetMoveSpeed = targetVel.Length() / 5.0f; // target speed per sim-frame during tracking interval targetMoveDir = targetVel / (targetMoveSpeed * 5.0f); // target direction of movement } const float dgunDelay = targetDist / commanderWD->projectilespeed; // sim-frames needed for dgun to reach target position const float3 leadPos = targetMoveDir * (targetMoveSpeed * dgunDelay); const float3 dgunPos = curTargetPos + leadPos; // position where target will be in <dgunDelay> frames const float maxRange = ai->cb->GetUnitMaxRange(commanderID); bool haveClearShot = true; int numSegments = 0; AIHCTraceRay rayData; float rayLen = maxRange * 1.1f; float3 rayPos = commanderPos; float3 rayDir = targetDif / targetDist; rayDir.y = 0.0f; while (haveClearShot && (rayLen >= 1.0f)) { rayData.rayPos = rayPos; rayData.rayDir = targetDif / targetDist; rayData.rayLen = rayLen; rayData.srcUID = commanderID; rayData.hitUID = -1; rayData.flags = 0; // modifies hitUID and rayLen ai->ccb->HandleCommand(AIHCTraceRayId, &rayData); // note: even if hitUnitID is -1, we can still end up destroying // our own units because dgun projectiles keep hugging the ground // rather than being absorbed by it on impact (which is assumed by // the trace) if (rayData.hitUID != -1) { if (ai->cb->GetUnitAllyTeam(rayData.hitUID) == ai->cb->GetMyAllyTeam()) { // hitUID is an allied unit haveClearShot = false; } else { // hitUID is an enemy unit rayPos = ai->ccb->GetUnitPos(rayData.hitUID); } } // make sure we always terminate rayLen -= rayData.rayLen; } // multiply by 0.9 to ensure commander does not have to walk if ((commanderPos - dgunPos).Length() < maxRange * 0.9f) { bool canDGun = (ai->cb->GetEnergy() >= DGUN_MIN_ENERGY_LEVEL) && haveClearShot && (udef != NULL && !udef->weapons.empty()); if (canDGun) { IssueOrder(dgunPos, CMD_DGUN, 0); } else { bool bDanger = ai->tm->ThreatAtThisPoint(commanderPos/*curTargetPos*/) > ai->tm->GetAverageThreat(); if (bDanger) { state.Reset(currentFrame, true); } else { if (ai->cb->GetUnitHealth(state.targetID) < ai->cb->GetUnitMaxHealth(state.targetID) * 0.5f) { IssueOrder(state.targetID, CMD_RECLAIM, 0); } else { IssueOrder(state.targetID, CMD_CAPTURE, 0); } } } } else { state.Reset(currentFrame, true); } } state.Reset(currentFrame, false); }
CStarburstProjectile::CStarburstProjectile( const float3& pos, const float3& speed, CUnit* owner, float3 targetPos, float areaOfEffect, float maxSpeed, float tracking, int uptime, CUnit* target, const WeaponDef* weaponDef, CWeaponProjectile* interceptTarget, float maxdistance, float3 aimError): CWeaponProjectile(pos, speed, owner, target, targetPos, weaponDef, interceptTarget, 200), tracking(tracking), maxSpeed(maxSpeed), areaOfEffect(areaOfEffect), age(0), oldSmoke(pos), aimError(aimError), drawTrail(true), numParts(0), doturn(true), curCallback(0), numCallback(0), missileAge(0), distanceToTravel(maxdistance) { projectileType = WEAPON_STARBURST_PROJECTILE; this->uptime = uptime; if (weaponDef) { if (weaponDef->flighttime == 0) { ttl = (int) std::min(3000.0f, uptime + weaponDef->range / maxSpeed + 100); } else { ttl = weaponDef->flighttime; } } maxGoodDif = cos(tracking * 0.6f); curSpeed = speed.Length(); dir = speed / curSpeed; oldSmokeDir = dir; drawRadius = maxSpeed * 8; numCallback = new int; *numCallback = 0; float3 camDir=(pos-camera->pos).Normalize(); if(camera->pos.distance(pos)*0.2f+(1-fabs(camDir.dot(dir)))*3000 < 200) drawTrail=false; for(int a = 0; a < 5; ++a) { oldInfos[a]=new OldInfo; oldInfos[a]->dir=dir; oldInfos[a]->pos=pos; oldInfos[a]->speedf=curSpeed; for(float aa = 0; aa < curSpeed + 0.6f; aa += 0.15f) { float ageMod = 1.0f; oldInfos[a]->ageMods.push_back(ageMod); } } castShadow = true; #ifdef TRACE_SYNC tracefile << "New starburst rocket: "; tracefile << pos.x << " " << pos.y << " " << pos.z << " " << speed.x << " " << speed.y << " " << speed.z << "\n"; #endif if (!cegTag.empty()) { ceg.Load(explGenHandler, cegTag); } }
CMissileProjectile::CMissileProjectile( const float3& pos, const float3& speed, CUnit* owner, float areaOfEffect, float maxSpeed, int ttl, CUnit* target, const WeaponDef* weaponDef, float3 targetPos) : CWeaponProjectile(pos, speed, owner, target, targetPos, weaponDef, NULL, ttl) , maxSpeed(maxSpeed) , areaOfEffect(areaOfEffect) , age(0) , oldSmoke(pos) , target(target) , decoyTarget(NULL) , drawTrail(true) , numParts(0) , targPos(targetPos) , isWobbling(weaponDef? (weaponDef->wobble > 0): false) , wobbleDir(ZeroVector) , wobbleTime(1) , wobbleDif(ZeroVector) , isDancing(weaponDef? (weaponDef->dance > 0): false) , danceTime(1) , danceMove(ZeroVector) , danceCenter(ZeroVector) , extraHeightTime(0) { projectileType = WEAPON_MISSILE_PROJECTILE; curSpeed = speed.Length(); dir = speed / curSpeed; oldDir = dir; if (target) { AddDeathDependence(target); } SetRadius(0.0f); if (weaponDef) { model = LoadModel(weaponDef); if (model) { SetRadius(model->radius); } } drawRadius = radius + maxSpeed * 8; float3 camDir = (pos - camera->pos).Normalize(); if ((camera->pos.distance(pos) * 0.2f + (1 - fabs(camDir.dot(dir))) * 3000) < 200) { drawTrail = false; } castShadow = true; #ifdef TRACE_SYNC tracefile << "New missile: "; tracefile << pos.x << " " << pos.y << " " << pos.z << " " << speed.x << " " << speed.y << " " << speed.z << "\n"; #endif if (target) { target->IncomingMissile(this); } if ((weaponDef) && (weaponDef->trajectoryHeight > 0)) { float dist = pos.distance(targPos); extraHeight = (dist * weaponDef->trajectoryHeight); if (dist < maxSpeed) { dist = maxSpeed; } extraHeightTime = (int)(dist / maxSpeed); extraHeightDecay = extraHeight / extraHeightTime; } cegID = gCEG->Load(explGenHandler, cegTag); }
float3 float3::Reflect(const float3 &normal) const { assume2(normal.IsNormalized(), normal.SerializeToCodeString(), normal.Length()); return 2.f * this->ProjectToNorm(normal) - *this; }
bool float3::IsPerpendicular(const float3 &other, float epsilon) const { return fabs(Dot(other)) <= epsilon * Length() * other.Length(); }
void CFreeController::Update() { if (!globalRendering->active) { vel = ZeroVector; avel = ZeroVector; prevVel = vel; prevAvel = avel; return; } // safeties velTime = max(0.1f, velTime); avelTime = max(0.1f, avelTime); // save some old state const float ctrlVelY = vel.y; const float3 prevPos = pos; // setup the time fractions const float ft = globalRendering->lastFrameTime; const float nt = (ft / velTime); // next time factor const float pt = (1.0f - nt); // prev time factor const float ant = (ft / avelTime); // next time factor const float apt = (1.0f - ant); // prev time factor // adjustment to match the ground slope float autoTiltVel = 0.0f; if (gndLock && (autoTilt > 0.0f)) { const float gndHeight = ground->GetHeightReal(pos.x, pos.z, false); if (pos.y < (gndHeight + gndOffset + 1.0f)) { float3 hDir; hDir.y = 0.0f; hDir.x = (float)math::sin(camera->rot.y); hDir.z = (float)math::cos(camera->rot.y); const float3 gndNormal = ground->GetSmoothNormal(pos.x, pos.z, false); const float dot = gndNormal.dot(hDir); const float gndRotX = (float)math::acos(dot) - (PI * 0.5f); const float rotXdiff = (gndRotX - camera->rot.x); autoTiltVel = (autoTilt * rotXdiff); } } // convert control velocity into position velocity if (!tracking) { if (goForward) { const float3 tmpVel((camera->forward * vel.x) + (UpVector * vel.y) + (camera->right * vel.z)); vel = tmpVel; } else { float3 forwardNoY(camera->forward.x, 0.0f, camera->forward.z); forwardNoY.ANormalize(); const float3 tmpVel((forwardNoY * vel.x) + (UpVector * vel.y) + (camera->right * vel.z)); vel = tmpVel; } } // smooth the velocities vel = (vel * nt) + (prevVel * pt); avel = (avel * ant) + (prevAvel * apt); // no smoothing for gravity (still isn't right) if (gndLock) { const float dGrav = (gravity * ft); vel.y += dGrav; if (slide > 0.0f) { const float gndHeight = ground->GetHeightReal(pos.x, pos.z, false); if (pos.y < (gndHeight + gndOffset + 1.0f)) { const float3 gndNormal = ground->GetSmoothNormal(pos.x, pos.z, false); const float dotVal = gndNormal.y; const float scale = (dotVal * slide * -dGrav); vel.x += (gndNormal.x * scale); vel.z += (gndNormal.z * scale); } } } // set the new position/rotation if (!tracking) { pos += (vel * ft); camera->rot += (avel * ft); camera->rot.x += (autoTiltVel * ft); // note that this is not smoothed } else { // speed along the tracking direction varies with distance const float3 diff = (pos - trackPos); if (goForward) { const float dist = max(0.1f, diff.Length()); const float nomDist = 512.0f; float speedScale = (dist / nomDist); speedScale = max(0.25f, min(16.0f, speedScale)); const float delta = -vel.x * (ft * speedScale); const float newDist = max(trackRadius, (dist + delta)); const float scale = (newDist / dist); pos = trackPos + (diff * scale); pos.y += (vel.y * ft); } else { const float dist = max(0.1f, diff.Length2D()); const float nomDist = 512.0f; float speedScale = (dist / nomDist); speedScale = max(0.25f, min(16.0f, speedScale)); const float delta = -vel.x * (ft * speedScale); const float newDist = max(trackRadius, (dist + delta)); const float scale = (newDist / dist); pos.x = trackPos.x + (scale * diff.x); pos.z = trackPos.z + (scale * diff.z); pos.y += (vel.y * ft); } // convert the angular velocity into its positional change const float3 diff2 = (pos - trackPos); const float deltaRad = (avel.y * ft); const float cos_val = math::cos(deltaRad); const float sin_val = math::sin(deltaRad); pos.x = trackPos.x + ((cos_val * diff2.x) + (sin_val * diff2.z)); pos.z = trackPos.z + ((cos_val * diff2.z) - (sin_val * diff2.x)); } // setup ground lock const float gndHeight = ground->GetHeightReal(pos.x, pos.z, false); if (keyInput->IsKeyPressed(SDLK_LSHIFT)) { if (ctrlVelY > 0.0f) { gndLock = false; } else if ((gndOffset > 0.0f) && (ctrlVelY < 0.0f) && (pos.y < (gndHeight + gndOffset))) { gndLock = true; } } // positional clamps if (gndOffset < 0.0f) { pos.y = (gndHeight - gndOffset); vel.y = 0.0f; } else if (gndLock && (gravity >= 0.0f)) { pos.y = (gndHeight + gndOffset); vel.y = 0.0f; } else if (gndOffset > 0.0f) { const float minHeight = (gndHeight + gndOffset); if (pos.y < minHeight) { pos.y = minHeight; if (gndLock) { vel.y = min(math::fabs(scrollSpeed), ((minHeight - prevPos.y) / ft)); } else { vel.y = 0.0f; } } } // angular clamps const float xRotLimit = (PI * 0.4999f); if (camera->rot.x > xRotLimit) { camera->rot.x = xRotLimit; avel.x = 0.0f; } else if (camera->rot.x < -xRotLimit) { camera->rot.x = -xRotLimit; avel.x = 0.0f; } camera->rot.y = math::fmod(camera->rot.y, PI * 2.0f); // setup for the next loop prevVel = vel; prevAvel = avel; vel = ZeroVector; avel = ZeroVector; tracking = false; }
float4 float4::Reflect3(const float3 &normal) const { assume2(normal.IsNormalized(), normal.SerializeToCodeString(), normal.Length()); assume(EqualAbs(w, 0)); return 2.f * this->ProjectToNorm3(normal) - *this; }