weapon.cpp
来自「这是整套横扫千军3D版游戏的源码」· C++ 代码 · 共 894 行 · 第 1/2 页
CPP
894 行
owner->cob->Call(COBFN_EndBurst+weaponNum);
}
#ifdef TRACE_SYNC
tracefile << "Weapon fire: ";
tracefile << weaponPos.x << " " << weaponPos.y << " " << weaponPos.z << " " << targetPos.x << " " << targetPos.y << " " << targetPos.z << "\n";
#endif
}
}
bool CWeapon::AttackGround(float3 pos, bool userTarget)
{
if (!userTarget && weaponDef->noAutoTarget) {
return false;
}
if (weaponDef->interceptor || !weaponDef->canAttackGround ||
(weaponDef->onlyTargetCategory != 0xffffffff)) {
return false;
}
if (!weaponDef->waterweapon && (pos.y < 1.0f)) {
pos.y = 1.0f;
}
weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
if(weaponMuzzlePos.y<ground->GetHeight2(weaponMuzzlePos.x,weaponMuzzlePos.z))
weaponMuzzlePos=owner->pos+UpVector*10; //hope that we are underground because we are a popup weapon and will come above ground later
if(!TryTarget(pos,userTarget,0))
return false;
if(targetUnit){
DeleteDeathDependence(targetUnit);
targetUnit=0;
}
haveUserTarget=userTarget;
targetType=Target_Pos;
targetPos=pos;
return true;
}
bool CWeapon::AttackUnit(CUnit *unit, bool userTarget)
{
if((!userTarget && weaponDef->noAutoTarget))
return false;
if(weaponDef->interceptor)
return false;
weaponPos= owner->pos + owner->frontdir * relWeaponPos.z
+ owner->updir * relWeaponPos.y + owner->rightdir * relWeaponPos.x;
weaponMuzzlePos= owner->pos + owner->frontdir * relWeaponMuzzlePos.z
+ owner->updir * relWeaponMuzzlePos.y + owner->rightdir * relWeaponMuzzlePos.x;
if(weaponMuzzlePos.y < ground->GetHeight2(weaponMuzzlePos.x, weaponMuzzlePos.z))
weaponMuzzlePos = owner->pos + UpVector * 10;
//hope that we are underground because we are a popup weapon and will come above ground later
if(!unit){
if(targetType!=Target_Unit) //make the unit be more likely to keep the current target if user start to move it
targetType=Target_None;
haveUserTarget=false;
return false;
}
float3 tempTargetPos(helper->GetUnitErrorPos(unit,owner->allyteam));
tempTargetPos+=errorVector*(weaponDef->targetMoveError*30*unit->speed.Length()*(1.0f-owner->limExperience));
float appHeight=ground->GetApproximateHeight(tempTargetPos.x,tempTargetPos.z)+2;
if(tempTargetPos.y < appHeight)
tempTargetPos.y=appHeight;
if(!TryTarget(tempTargetPos,userTarget,unit))
return false;
if(targetUnit){
DeleteDeathDependence(targetUnit);
targetUnit=0;
}
haveUserTarget=userTarget;
targetType=Target_Unit;
targetUnit=unit;
targetPos=tempTargetPos;
AddDeathDependence(targetUnit);
avoidTarget=false;
return true;
}
void CWeapon::HoldFire()
{
if(targetUnit){
DeleteDeathDependence(targetUnit);
targetUnit=0;
}
targetType=Target_None;
haveUserTarget=false;
}
void CWeapon::SlowUpdate()
{
SlowUpdate(false);
}
inline bool CWeapon::ShouldCheckForNewTarget() const
{
if (weaponDef->noAutoTarget) { return false; }
if (owner->fireState < 2) { return false; }
if (haveUserTarget) { return false; }
if (targetType == Target_None) { return true; }
if (avoidTarget) { return true; }
if (targetType == Target_Unit) {
if (targetUnit->category & badTargetCategory) {
return true;
}
}
if (gs->frameNum > (lastTargetRetry + 65)) {
return true;
}
return false;
}
void CWeapon::SlowUpdate(bool noAutoTargetOverride)
{
#ifdef TRACE_SYNC
tracefile << "Weapon slow update: ";
tracefile << owner->id << " " << weaponNum << "\n";
#endif
std::vector<int> args;
args.push_back(0);
if(useWeaponPosForAim){ //If we can't get a line of fire from the muzzle try the aim piece instead since the weapon may just be turned in a wrong way
owner->cob->Call(COBFN_QueryPrimary+weaponNum,args);
if(useWeaponPosForAim>1)
useWeaponPosForAim--;
} else {
owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
}
relWeaponMuzzlePos=owner->localmodel->GetPiecePos(args[0]);
weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
if(weaponMuzzlePos.y<ground->GetHeight2(weaponMuzzlePos.x,weaponMuzzlePos.z))
weaponMuzzlePos=owner->pos+UpVector*10; //hope that we are underground because we are a popup weapon and will come above ground later
predictSpeedMod=1+(gs->randFloat()-0.5f)*2*(1-owner->limExperience);
if((targetPos-weaponPos).SqLength() < relWeaponPos.SqLength()*16)
hasCloseTarget=true;
else
hasCloseTarget=false;
if(targetType!=Target_None && !TryTarget(targetPos,haveUserTarget,targetUnit)){
HoldFire();
}
if(targetType==Target_Unit && targetUnit->isCloaked && !(targetUnit->losStatus[owner->allyteam] & (LOS_INLOS | LOS_INRADAR)))
HoldFire();
if (targetType==Target_Unit && !haveUserTarget && targetUnit->neutral && owner->fireState < 3)
HoldFire();
//happens if the target or the unit has switched teams
if (targetType==Target_Unit && !haveUserTarget && targetUnit->allyteam == owner->allyteam)
HoldFire();
if(slavedTo){ //use targets from the thing we are slaved to
if(targetUnit){
DeleteDeathDependence(targetUnit);
targetUnit=0;
}
targetType=Target_None;
if(slavedTo->targetType==Target_Unit){
float3 tp=helper->GetUnitErrorPos(slavedTo->targetUnit,owner->allyteam);
tp+=errorVector*(weaponDef->targetMoveError*30*slavedTo->targetUnit->speed.Length()*(1.0f-owner->limExperience));
if(TryTarget(tp,false,slavedTo->targetUnit)){
targetType=Target_Unit;
targetUnit=slavedTo->targetUnit;
targetPos=tp;
AddDeathDependence(targetUnit);
}
} else if(slavedTo->targetType==Target_Pos){
if(TryTarget(slavedTo->targetPos,false,0)){
targetType=Target_Pos;
targetPos=slavedTo->targetPos;
}
}
return;
}
/* owner->fireState>=2 && !haveUserTarget &&
if (!weaponDef->noAutoTarget && !noAutoTargetOverride) {
((targetType == Target_None) ||
((targetType == Target_Unit) &&
((targetUnit->category & badTargetCategory) ||
(targetUnit->neutral && (owner->fireState < 3)))) ||
(gs->frameNum > lastTargetRetry + 65))) {
*/
if (!noAutoTargetOverride && ShouldCheckForNewTarget()) {
lastTargetRetry = gs->frameNum;
std::map<float, CUnit*> targets;
helper->GenerateTargets(this, targetUnit, targets);
for (std::map<float,CUnit*>::iterator ti=targets.begin();ti!=targets.end();++ti) {
if (ti->second->neutral && (owner->fireState < 3)) {
continue;
}
if (targetUnit && (ti->second->category & badTargetCategory)) {
continue;
}
float3 tp(ti->second->midPos);
tp+=errorVector*(weaponDef->targetMoveError*30*ti->second->speed.Length()*(1.0f-owner->limExperience));
float appHeight=ground->GetApproximateHeight(tp.x,tp.z)+2;
if (tp.y < appHeight) {
tp.y = appHeight;
}
if (TryTarget(tp, false, ti->second)) {
if (targetUnit) {
DeleteDeathDependence(targetUnit);
}
targetType = Target_Unit;
targetUnit = ti->second;
targetPos = tp;
AddDeathDependence(targetUnit);
break;
}
}
}
if (targetType != Target_None) {
owner->haveTarget = true;
if (haveUserTarget) {
owner->haveUserTarget = true;
}
} else { //if we cant target anything try switching aim point
if (useWeaponPosForAim && (useWeaponPosForAim == 1)) {
useWeaponPosForAim = 0;
} else {
useWeaponPosForAim = 1;
}
}
}
void CWeapon::DependentDied(CObject *o)
{
if(o==targetUnit){
targetUnit=0;
if(targetType==Target_Unit){
targetType=Target_None;
haveUserTarget=false;
}
}
if(weaponDef->interceptor){
incoming.remove((CWeaponProjectile*)o);
}
if (o==interceptTarget)
interceptTarget = 0;
}
bool CWeapon::TryTarget(const float3 &pos,bool userTarget,CUnit* unit)
{
if (unit && !(onlyTargetCategory & unit->category)) {
return false;
}
if(unit && ((unit->isDead && (modInfo.fireAtKilled==0)) ||
(unit->crashing && (modInfo.fireAtCrashing==0)))) {
return false;
}
if (weaponDef->stockpile && !numStockpiled) {
return false;
}
float3 dif=pos-weaponMuzzlePos;
float heightDiff; // negative when target below owner
if (targetBorder != 0 && unit) {
float3 diff(dif);
diff.Normalize();
// weapon inside target sphere
if (dif.SqLength() < unit->sqRadius*targetBorder*targetBorder) {
dif -= diff*(dif.Length() - 10); // a hack
//logOutput << "inside\n";
} else {
dif -= diff*(unit->radius*targetBorder);
//logOutput << "outside\n";
}
//geometricObjects->AddLine(weaponMuzzlePos, weaponMuzzlePos+dif, 3, 0, 16);
heightDiff = (weaponPos.y + dif.y) - owner->pos.y;
} else {
heightDiff = pos.y - owner->pos.y;
}
float r;
if (!unit || cylinderTargetting < 0.01) {
r=GetRange2D(heightDiff*heightMod);
} else {
if (cylinderTargetting * range > fabs(heightDiff)*heightMod) {
r = GetRange2D(0);
} else {
r = 0;
}
}
if(dif.SqLength2D()>=r*r)
return false;
if(maxMainDirAngleDif>-0.999f){
dif.Normalize();
float3 modMainDir=owner->frontdir*mainDir.z+owner->rightdir*mainDir.x+owner->updir*mainDir.y;
// geometricObjects->AddLine(weaponPos,weaponPos+modMainDir*50,3,0,16);
if(modMainDir.dot(dif)<maxMainDirAngleDif)
return false;
}
return true;
}
bool CWeapon::TryTarget(CUnit* unit, bool userTarget){
float3 tempTargetPos(helper->GetUnitErrorPos(unit,owner->allyteam));
tempTargetPos+=errorVector*(weaponDef->targetMoveError*30*unit->speed.Length()*(1.0f-owner->limExperience));
float appHeight=ground->GetApproximateHeight(tempTargetPos.x,tempTargetPos.z)+2;
if(tempTargetPos.y < appHeight){
tempTargetPos.y=appHeight;
}
return TryTarget(tempTargetPos,userTarget,unit);
}
bool CWeapon::TryTargetRotate(CUnit* unit, bool userTarget){
float3 tempTargetPos(helper->GetUnitErrorPos(unit,owner->allyteam));
tempTargetPos+=errorVector*(weaponDef->targetMoveError*30*unit->speed.Length()*(1.0f-owner->limExperience));
float appHeight=ground->GetApproximateHeight(tempTargetPos.x,tempTargetPos.z)+2;
if(tempTargetPos.y < appHeight){
tempTargetPos.y=appHeight;
}
short weaponHeadding = GetHeadingFromVector(mainDir.x, mainDir.z);
short enemyHeadding = GetHeadingFromVector(
tempTargetPos.x - weaponPos.x, tempTargetPos.z - weaponPos.z);
return TryTargetHeading(enemyHeadding - weaponHeadding, tempTargetPos,userTarget, unit);
}
bool CWeapon::TryTargetRotate(float3 pos, bool userTarget) {
if (!userTarget && weaponDef->noAutoTarget) {
return false;
}
if (weaponDef->interceptor || !weaponDef->canAttackGround ||
(weaponDef->onlyTargetCategory != 0xffffffff)) {
return false;
}
if (!weaponDef->waterweapon && pos.y < 1) {
pos.y = 1;
}
short weaponHeading = GetHeadingFromVector(mainDir.x, mainDir.z);
short enemyHeading = GetHeadingFromVector(
pos.x - weaponPos.x, pos.z - weaponPos.z);
return TryTargetHeading(enemyHeading - weaponHeading, pos, userTarget, 0);
}
bool CWeapon::TryTargetHeading(short heading, float3 pos, bool userTarget, CUnit* unit) {
float3 tempfrontdir(owner->frontdir);
float3 temprightdir(owner->rightdir);
short tempHeadding = owner->heading;
owner->heading = heading;
owner->frontdir = GetVectorFromHeading(owner->heading);
owner->rightdir = owner->frontdir.cross(owner->updir);
weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
bool val = TryTarget(pos, userTarget, 0);
owner->frontdir = tempfrontdir;
owner->rightdir = temprightdir;
owner->heading = tempHeadding;
weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
return val;
}
void CWeapon::Init(void)
{
std::vector<int> args;
args.push_back(0);
owner->cob->Call(COBFN_AimFromPrimary+weaponNum,args);
relWeaponPos=owner->localmodel->GetPiecePos(args[0]);
weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
owner->cob->Call(COBFN_QueryPrimary+weaponNum,args);
relWeaponMuzzlePos=owner->localmodel->GetPiecePos(args[0]);
weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
// logOutput.Print("RelPos %f %f %f",relWeaponPos.x,relWeaponPos.y,relWeaponPos.z);
if (range > owner->maxRange) {
owner->maxRange = range;
}
muzzleFlareSize = min(areaOfEffect*0.2f,min(1500.f,weaponDef->damages[0])*0.003f);
if (weaponDef->interceptor)
interceptHandler.AddInterceptorWeapon(this);
if(weaponDef->stockpile){
owner->stockpileWeapon = this;
owner->commandAI->AddStockpileWeapon(this);
}
if (weaponDef->isShield) {
if ((owner->shieldWeapon == NULL) ||
(owner->shieldWeapon->weaponDef->shieldRadius < weaponDef->shieldRadius)) {
owner->shieldWeapon = this;
}
}
}
void CWeapon::ScriptReady(void)
{
angleGood=true;
}
void CWeapon::CheckIntercept(void)
{
targetType=Target_None;
for(std::list<CWeaponProjectile*>::iterator pi=incoming.begin();pi!=incoming.end();++pi){
if((*pi)->targeted)
continue;
targetType=Target_Intercept;
interceptTarget=*pi;
targetPos=(*pi)->pos;
break;
}
}
float CWeapon::GetRange2D(float yDiff) const
{
float root1 = range*range - yDiff*yDiff;
if(root1 < 0){
return 0;
} else {
return sqrt(root1);
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?