bool CUnit::AddBuildPower(float amount,CUnit* builder) { if(amount>0) { //build/repair if(!beingBuilt && health>=maxHealth) return false; lastNanoAdd=gs->frameNum; float part=amount/buildTime; if(beingBuilt) { float metalUse=metalCost*part; float energyUse=energyCost*part; if (gs->Team(builder->team)->metal >= metalUse && gs->Team(builder->team)->energy >= energyUse) { builder->UseMetal(metalUse); builder->UseEnergy(energyUse); health+=maxHealth*part; buildProgress+=part; if(buildProgress>=1) { if(health>maxHealth) health=maxHealth; FinishedBuilding(); } return true; } return false; } else { if(health<maxHealth) { health+=maxHealth*part; if(health>maxHealth) health=maxHealth; return true; } return false; } } else { //reclaim if(health<0) return false; restTime=0; float part=amount/buildTime; health+=maxHealth*part; if(beingBuilt) { builder->AddMetal(metalCost*-part); buildProgress+=part; if(buildProgress<0 || health<0) { KillUnit(false,true,0); return false; } } else { if(health<0) { builder->AddMetal(metalCost); KillUnit(false,true,0); return false; } } return true; } return false; }
void CUnit::FinishedBuilding(void) { beingBuilt = false; buildProgress = 1.0f; if (soloBuilder) { DeleteDeathDependence(soloBuilder); soloBuilder = NULL; } if (!(immobile && (mass == 100000))) { mass = unitDef->mass; //set this now so that the unit is harder to move during build } ChangeLos(realLosRadius,realAirLosRadius); if (unitDef->startCloaked) { wantCloak = true; isCloaked = true; } if (unitDef->windGenerator>0) { if (wind.curStrength > unitDef->windGenerator) { cob->Call(COBFN_SetSpeed, (int)(unitDef->windGenerator * 3000.0f)); } else { cob->Call(COBFN_SetSpeed, (int)(wind.curStrength * 3000.0f)); } cob->Call(COBFN_SetDirection, (int)GetHeadingFromVector(-wind.curDir.x, -wind.curDir.z)); } if (unitDef->activateWhenBuilt) { Activate(); } gs->Team(team)->metalStorage += unitDef->metalStorage; gs->Team(team)->energyStorage += unitDef->energyStorage; //Sets the frontdir in sync with heading. frontdir = GetVectorFromHeading(heading) + float3(0,frontdir.y,0); if (unitDef->isAirBase) { airBaseHandler->RegisterAirBase(this); } luaCallIns.UnitFinished(this); globalAI->UnitFinished(this); if (unitDef->isFeature) { UnBlock(); CFeature* f = featureHandler->CreateWreckage(pos, wreckName, heading, buildFacing, 0, team, false, ""); if (f) { f->blockHeightChanges = true; } KillUnit(false, true, 0); } }
int BrigadeClass::UpdateParentStatistics (void) { GridIndex nx,ny,x,y; int engaged=0,combat=0,loss=0,te=0; Unit e; // Update unit wide statistics. NOTE: some delay here- since elements are unmoved. nx = ny = te = 0; e = GetFirstUnitElement(); while (e) { if (e->Engaged()) engaged = 1; if (e->Combat()) combat = 1; if (e->Losses()) loss = 1; e->GetLocation(&x,&y); // nx += x; // ny += y; if (!nx && !ny) e->GetLocation(&nx,&ny); te++; e = GetNextUnitElement(); } if (!te) { KillUnit(); return 0; } if (!engaged) { SetEngaged(0); SetTarget(NULL); } SetEngaged(engaged); SetCombat(combat); SetLosses(loss); // Set our new averaged position // x = nx / te; // y = ny / te; // SetLocation(x,y); ShiAssert (nx && ny); // Set our position to our first element SetLocation(nx,ny); return te; }
int SquadronClass::MoveUnit (CampaignTime time) { GridIndex x,y,nx,ny; VuGridIterator* myit = NULL; Objective o,bo=NULL; float fd; int range,score,i,want_alert=0,bs=-999; CampEntity ab; /* Don't recall squadrons - per Gilman if (GetTotalVehicles() < GetFullstrengthVehicles() / 4) { if (this == FalconLocalSession->GetPlayerSquadron()) PostMessage(FalconDisplay.appWin,FM_SQUADRON_RECALLED,0,0); KillUnit(); } */ //TJL 11/02/03 Enable Scramble missions if (g_bScramble) { // Set up an alert bird for this squadron if (rating[ARO_CA] > 4) { // KCK: Check if we have available aircraft // NOTE: We might want to make sure we always ask for at least one // alert flight. for (i=0; i<VEHICLES_PER_UNIT/2; i++) { if (!schedule[i]) want_alert = 1; } if (want_alert) { //#ifdef DEBUG MonoPrint("Requesting alert bird for squadron #%d.\n",GetCampID()); //#endif MissionRequestClass mis; // JB 010728 Make the wait time configurable // MN 020102 This is not the relocation timer - check above // mis.tot = Camp_GetCurrentTime() + g_nRelocationWait * CampaignHours; // hang around for a few hours mis.tot = Camp_GetCurrentTime() + 3 * CampaignHours; mis.requesterID = Id(); mis.who = GetTeam(); mis.vs = GetEnemyTeam(mis.who); mis.tot_type = TYPE_NE; GetLocation(&mis.tx,&mis.ty); mis.targetID = FalconNullId; mis.mission = AMIS_ALERT; mis.roe_check = ROE_AIR_ENGAGE; mis.flags = REQF_ONETRY | REQF_USE_REQ_SQUAD | REQF_USERESERVES; mis.priority = 255; // High priority mis.RequestMission(); } } } else { } //TJL 11/02/03 End Scramble // OW AB Relocation fix if(g_bEnableABRelocation) { if(SimLibElapsedTime < 32450000.0f) return 0; //me123 dont relocate before the campaign has begun } ab = FindEntity(airbase_id); // A.S. begin CampEntity ab_old; // A.S. new variable if (g_bHelosReloc) { ab_old = ab; } // A.S. end ShiAssert (!ab || ab->IsObjective() || ab->IsTaskForce() || (ab == this && DontPlan())); if (!ab || ab->IsObjective() || ab == this) { // Don't plan flag used to mean don't rebase for squadrons if (DontPlan()) { // 2001-08-06 MODIFIED BY S.G. FRIENDLY BASE WILL DO THE JOB ALL RIGHT. NO NEED TO LIMIT IT TO OUR TEAM. // if (ab->GetTeam() != GetTeam()) if (!ab || !GetRoE(ab->GetTeam(), GetTeam(), ROE_AIR_USE_BASES)) { if (this == FalconLocalSession->GetPlayerSquadron()) PostMessage(FalconDisplay.appWin,FM_SQUADRON_RECALLED,0,0); KillUnit(); } return 0; } // If airbase is non-functional, force a rebase // 2001-08-03 MODIFIED BY S.G. ONLY IF CAPTURED SHOULD IT RELOCATE. DESTROYED AIRBASE STILL OWN BY US WILL REPAIR EVENTUALLY. // if (ab && ab->IsObjective() && ((Objective)ab)->GetAdjustedDataRate() < 1) if (ab && ab->IsObjective() && !GetRoE(ab->GetTeam(), GetTeam(), ROE_AIR_USE_BASES)) ab = NULL; // Added by A.S. 1.1.2002. Helos will be reallocated if armybase is destoyed. if (g_bHelosReloc) { if (ab && ab->IsObjective() && IsHelicopter() && ((Objective)ab)->GetAdjustedDataRate() < 1) { ab = NULL; // FILE *deb; // deb = fopen("c:\\temp\\realloc.txt", "a"); // fprintf(deb, "ArmyBase ID = %d team = %x type = %x TIME = %d\n", ab_old, ab_old->GetTeam, ab_old->GetType, TheCampaign.CurrentTime/(3600*1000)); // fclose(deb); } } // A.S. end // Check airbase location - if to near or far from front, relocate GetLocation(&x,&y); fd = DistanceToFront(x,y); range = GetUnitRange(); // 2001-07-05 MODIFIED BY S.G. DON'T RELOCATE IF TOO FAR FROM FLOT IF GLOBALLY SET TO ACT THAT WAY // if (fd < 999.0F && (fd < range/30 || fd > range/3 || !ab)) // We're to close or to far from the front or don't have an airbase if (fd < 999.0F && (fd < range/30 || (!(g_nAirbaseReloc & AirBaseRelocNoFar) && fd > range/3) || !ab)) // We're to close or to far from the front or don't have an airbase { // Find a better base for us UnitClassDataType *uc = GetUnitClassData(); ATMAirbaseClass *atmbase; Team us = GetTeam(); CAMPREGLIST_ITERATOR myit(AllObjList); o = (Objective) myit.GetFirst(); while (o) { // 2001-07-05 MODIFIED BY S.G. ONLY USE YOUR OWN AIRBASE IF GLOBALLY SET TO ACT THAT WAY // if ((o->GetType() == TYPE_AIRBASE && !IsHelicopter() && GetRoE(o->GetTeam(),us,ROE_AIR_USE_BASES)) || // (o->GetType() == TYPE_ARMYBASE && IsHelicopter() && GetRoE(o->GetTeam(),us,ROE_AIR_USE_BASES))) int enter = FALSE; if (g_nAirbaseReloc & AirBaseRelocTeamOnly) { if ((o->GetType() == TYPE_AIRBASE && !IsHelicopter() && o->GetTeam() == us) || (o->GetType() == TYPE_ARMYBASE && IsHelicopter() && o->GetTeam() == us)) enter = TRUE; } else { if ((o->GetType() == TYPE_AIRBASE && !IsHelicopter() && GetRoE(o->GetTeam(),us,ROE_AIR_USE_BASES)) || (o->GetType() == TYPE_ARMYBASE && IsHelicopter() && GetRoE(o->GetTeam(),us,ROE_AIR_USE_BASES))) enter = TRUE; } if (enter) // END OF MODIFIED SECTION { o->GetLocation(&nx,&ny); fd = DistanceToFront(nx,ny); if (fd > range/15 && o->GetAdjustedDataRate() > 0) { score = o->GetObjectiveStatus()*5 - FloatToInt32(fd); // Adjust by number of squadrons already based here. atmbase = TeamInfo[us]->atm->FindATMAirbase (o->Id()); if (atmbase && atmbase->usage) // JB 010328 from Mad__Max //score /= atmbase->usage; { if (o != ab) score /= (atmbase->usage+1); if (o == ab) score /= atmbase->usage; } // JB 010328 from Mad__Max if (score > bs) { bo = o; bs = score; } } } o = (Objective) myit.GetNext(); } if (bo) { if (bo != ab) { bo->GetLocation(&nx,&ny); SetLocation(nx,ny); SetUnitAirbase(bo->Id()); TeamInfo[us]->atm->AddToAirbaseList(bo); if (this == FalconLocalSession->GetPlayerSquadron()) PostMessage(FalconDisplay.appWin,FM_SQUADRON_REBASED,0,0); // 2001-07-05 MODIFIED BY S.G. RETASK IN ONE DAY ONLY // 020102 M.N. Variable relocate time squadronRetaskAt = Camp_GetCurrentTime() + CampaignHours * g_nRelocationWait; // A.S. begin: retask time for Helos only 1 hour if (g_bHelosReloc) { if (ab_old && ab_old->IsObjective() && ((Objective)ab_old)->GetAdjustedDataRate() < 1) { if ( IsHelicopter() ) { squadronRetaskAt = Camp_GetCurrentTime() + CampaignHours * 1; // FILE *deb; // deb = fopen("c:\\temp\\realloc.txt", "a"); // fprintf(deb, "====> squadronRetaskAt ID = %d ID_neu %d team = %x type = %x TIME = %d\n\n", ab_old, bo, ab_old->GetTeam, ab_old->GetType, TheCampaign.CurrentTime/(3600*1000)); // fclose(deb); } } } // A.S. end +++++++++++++++++ } } else { // We're lost if (this == FalconLocalSession->GetPlayerSquadron()) PostMessage(FalconDisplay.appWin,FM_SQUADRON_RECALLED,0,0); KillUnit(); return 0; } } } // Set up an alert bird for this squadron //TJL 10/31/03 Move This /* if (rating[ARO_CA] > 5) { // KCK: Check if we have available aircraft // NOTE: We might want to make sure we always ask for at least one // alert flight. for (i=0; i<VEHICLES_PER_UNIT/2; i++) { if (!schedule[i]) want_alert = 1; } if (want_alert) { #ifdef DEBUG // MonoPrint("Requesting alert bird for squadron #%d.\n",GetCampID()); #endif MissionRequestClass mis; // JB 010728 Make the wait time configurable // MN 020102 This is not the relocation timer - check above // mis.tot = Camp_GetCurrentTime() + g_nRelocationWait * CampaignHours; // hang around for a few hours mis.tot = Camp_GetCurrentTime() + 3 * CampaignHours; mis.requesterID = Id(); mis.who = GetTeam(); mis.vs = GetEnemyTeam(mis.who); mis.tot_type = TYPE_NE; GetLocation(&mis.tx,&mis.ty); mis.targetID = FalconNullId; mis.mission = AMIS_ALERT; mis.roe_check = ROE_AIR_ENGAGE; mis.flags = REQF_ONETRY | REQF_USE_REQ_SQUAD | REQF_USERESERVES; mis.priority = 255; // High priority mis.RequestMission(); } } */ return 0; }
bool MoveUnitTo( UnitData* pointerToUnitData, float newX, float newY ) { // Ignore dead units if( pointerToUnitData->health <= 0 ) return false; bool canMoveToCell = false; int newRow = int(newY); int newColumn = int(newX); int oldRow = int(pointerToUnitData->y); int oldColumn = int(pointerToUnitData->x); unsigned char unitSymbol = levelData[oldRow][oldColumn]; unsigned char destinationCellSymbol = levelData[newRow][newColumn]; int directionRow = newRow - oldRow; int directionColumn = newColumn - oldColumn; // All units actions switch( destinationCellSymbol ) { case CellSymbol_Empty: canMoveToCell = true; break; case CellSymbol_Abyss: KillUnit( pointerToUnitData ); break; case CellSymbol_Box: if( directionRow < 0 ) { levelData[newRow-1][newColumn] = CellSymbol_Crystal; levelData[newRow][newColumn] = CellSymbol_OpenedBox; } break; case CellSymbol_MushroomBox: if( directionRow < 0 ) { levelData[newRow-1][newColumn] = CellSymbol_Mushroom; levelData[newRow][newColumn] = CellSymbol_OpenedBox; } break; } // Only hero actions if( pointerToUnitData->type == UnitType_Hero ) { switch( destinationCellSymbol ) { case CellSymbol_Exit: isGameActive = false; break; case CellSymbol_Crystal: canMoveToCell = true; break; case CellSymbol_Mushroom: canMoveToCell = true; if( pointerToUnitData->health < 2 ) pointerToUnitData->health = 2; break; case CellSymbol_BrickWall: if( (directionRow < 0) && (pointerToUnitData->health > 1) ) levelData[newRow][newColumn] = CellSymbol_Empty; break; case CellSymbol_Goomba: if( directionRow > 0 ) { UnitData* unitData = GetUnitAt(newRow, newColumn); if( unitData != 0 ) { KillUnit( unitData ); pointerToUnitData->ySpeed = -GetUnitJumpSpeed(pointerToUnitData->type); } } break; } } // Only monsters actions else { switch( destinationCellSymbol ) { case CellSymbol_Hero: unitsData[heroIndex].health--; if( pointerToUnitData->xOrder == UnitOrder_Backward ) pointerToUnitData->xOrder = UnitOrder_Forward; else pointerToUnitData->xOrder = UnitOrder_Backward; break; default: UnitType unitType = GetUnitTypeFromCell( destinationCellSymbol ); if( unitType != UnitType_None ) { if( pointerToUnitData->xOrder == UnitOrder_Backward ) pointerToUnitData->xOrder = UnitOrder_Forward; else pointerToUnitData->xOrder = UnitOrder_Backward; } break; } } if( canMoveToCell ) { levelData[oldRow][oldColumn] = CellSymbol_Empty; pointerToUnitData->x = newX; pointerToUnitData->y = newY; levelData[newRow][newColumn] = unitSymbol; } return canMoveToCell; }
void CUnit::DoDamage(const DamageArray& damages, CUnit *attacker,const float3& impulse) { if(isDead) return; residualImpulse+=impulse/mass; moveType->ImpulseAdded(); float damage=damages[armorType]; if(damage<0) { // info->AddLine("Negative damage"); return; } if(attacker) { float3 adir=attacker->pos-pos; adir.Normalize(); bonusShieldDir+=adir*bonusShieldSaved; //not the best way to do it(but fast) bonusShieldDir.Normalize(); // info->AddLine("shield mult %f %f %i %i", 2-adir.dot(bonusShieldDir),bonusShieldSaved,id,attacker->id); bonusShieldSaved=0; damage*=1.4-adir.dot(bonusShieldDir)*0.5; } float3 hitDir = impulse; hitDir.y = 0; hitDir = -hitDir.Normalize(); std::vector<int> hitAngles; hitAngles.push_back((int)(500 * hitDir.z)); hitAngles.push_back((int)(500 * hitDir.x)); cob->Call(COBFN_HitByWeapon, hitAngles); damage*=curArmorMultiple; globalAI->UnitDamaged(this,attacker,damage); restTime=0; float experienceMod=1; if(damages.paralyzeDamageTime) { paralyzeDamage+=damage; experienceMod=0.1; //reduce experience for paralyzers if(health-paralyzeDamage<0) { if(stunned) experienceMod=0; //dont get any experience for paralyzing paralyzed enemy stunned=true; if(paralyzeDamage>health+(maxHealth*0.025*damages.paralyzeDamageTime)) { paralyzeDamage=health+(maxHealth*0.025*damages.paralyzeDamageTime); } } } else { // Dont log overkill damage (so dguns/nukes etc dont inflate values) float statsdamage = std::min(health, damage); if (attacker) gs->Team(attacker->team)->currentStats.damageDealt += statsdamage; gs->Team(team)->currentStats.damageReceived += statsdamage; health-=damage; } recentDamage+=damage; if(attacker!=0 && !gs->Ally(allyteam,attacker->allyteam)) { // info->AddLine("%s has %f/%f h attacker %s do %f d",tooltip.c_str(),health,maxHealth,attacker->tooltip.c_str(),damage); attacker->experience+=0.1*power/attacker->power*(damage+min(0.f,health))/maxHealth*experienceMod; attacker->ExperienceChange(); ENTER_UNSYNCED; if (((!unitDef->isCommander && uh->lastDamageWarning+100<gs->frameNum) || (unitDef->isCommander && uh->lastCmdDamageWarning+100<gs->frameNum)) && team==gu->myTeam && !camera->InView(midPos,radius+50) && !gu->spectating) { info->AddLine("%s is being attacked",unitDef->humanName.c_str()); info->SetLastMsgPos(pos); if(unitDef->isCommander || uh->lastDamageWarning+150<gs->frameNum) sound->PlaySound(unitDef->sounds.underattack.id,unitDef->isCommander?4:2); minimap->AddNotification(pos,float3(1,0.3,0.3),unitDef->isCommander?1:0.5); //todo: make compatible with new gui uh->lastDamageWarning=gs->frameNum; if(unitDef->isCommander) uh->lastCmdDamageWarning=gs->frameNum; } ENTER_SYNCED; } if(health<=0) { KillUnit(false,false,attacker); if(isDead && attacker!=0 && !gs->Ally(allyteam,attacker->allyteam) && !beingBuilt) { attacker->experience+=0.1*power/attacker->power; gs->Team(attacker->team)->currentStats.unitsKilled++; } } // if(attacker!=0 && attacker->team==team) // info->AddLine("FF by %i %s on %i %s",attacker->id,attacker->tooltip.c_str(),id,tooltip.c_str()); #ifdef TRACE_SYNC tracefile << "Damage: "; tracefile << id << " " << damage << "\n"; #endif }
void CUnit::SlowUpdate() { --nextPosErrorUpdate; if(nextPosErrorUpdate==0) { float3 newPosError(gs->randVector()); newPosError.y*=0.2; if(posErrorVector.dot(newPosError)<0) newPosError=-newPosError; posErrorDelta=(newPosError-posErrorVector)*(1.0/256); nextPosErrorUpdate=16; } for(int a=0; a<gs->activeAllyTeams; ++a) { if(losStatus[a] & LOS_INTEAM) { } else if(loshandler->InLos(this,a)) { if(!(losStatus[a]&LOS_INLOS)) { int prevLosStatus = losStatus[a]; if(mobility || beingBuilt) { losStatus[a]|=(LOS_INLOS | LOS_INRADAR); } else { losStatus[a]|=(LOS_INLOS | LOS_INRADAR | LOS_PREVLOS | LOS_CONTRADAR); } if(!(prevLosStatus&LOS_INRADAR)) { globalAI->UnitEnteredRadar(this,a); } globalAI->UnitEnteredLos(this,a); } } else if(radarhandler->InRadar(this,a)) { if((losStatus[a] & LOS_INLOS)) { globalAI->UnitLeftLos(this,a); losStatus[a]&= ~LOS_INLOS; } else if(!(losStatus[a] & LOS_INRADAR)) { losStatus[a]|= LOS_INRADAR; globalAI->UnitEnteredRadar(this,a); } } else { if((losStatus[a]&LOS_INRADAR)) { if((losStatus[a]&LOS_INLOS)) { globalAI->UnitLeftLos(this,a); globalAI->UnitLeftRadar(this,a); } else { globalAI->UnitLeftRadar(this,a); } losStatus[a]&= ~(LOS_INLOS | LOS_INRADAR | LOS_CONTRADAR); } } } if(paralyzeDamage>0) { paralyzeDamage-=maxHealth*(16.f/30.f/40.f); if(paralyzeDamage<0) paralyzeDamage=0; if(paralyzeDamage<health) stunned=false; } if(stunned) { isCloaked=false; return; } if(selfDCountdown && !stunned) { selfDCountdown--; if(selfDCountdown<=1) { if(!beingBuilt) KillUnit(true,false,0); else KillUnit(false,true,0); //avoid unfinished buildings making an explosion selfDCountdown=0; return; } ENTER_MIXED; if(selfDCountdown&1 && team==gu->myTeam) info->AddLine("%s: Self destruct in %i s",unitDef->humanName.c_str(),selfDCountdown/2); ENTER_SYNCED; } if(beingBuilt) { if(lastNanoAdd<gs->frameNum-200) { health-=maxHealth/(buildTime*0.03); buildProgress-=1/(buildTime*0.03); AddMetal(metalCost/(buildTime*0.03)); if(health<0) KillUnit(false,true,0); } return; } //below is stuff that shouldnt be run while being built lastSlowUpdate=gs->frameNum; commandAI->SlowUpdate(); moveType->SlowUpdate(); metalMake = metalMakeI + metalMakeold; metalUse = metalUseI+ metalUseold; energyMake = energyMakeI + energyMakeold; energyUse = energyUseI + energyUseold; metalMakeold = metalMakeI; metalUseold = metalUseI; energyMakeold = energyMakeI; energyUseold = energyUseI; metalMakeI=metalUseI=energyMakeI=energyUseI=0; AddMetal(unitDef->metalMake*0.5f); if(activated) { if(UseEnergy(unitDef->energyUpkeep*0.5f)) { if(unitDef->isMetalMaker) { AddMetal(unitDef->makesMetal*0.5f*uh->metalMakerEfficiency); uh->metalMakerIncome+=unitDef->makesMetal; } else { AddMetal(unitDef->makesMetal*0.5f); } if(unitDef->extractsMetal>0) AddMetal(metalExtract * 0.5f); } UseMetal(unitDef->metalUpkeep*0.5f); if(unitDef->windGenerator>0) { if(wind.curStrength > unitDef->windGenerator) { AddEnergy(unitDef->windGenerator*0.5f); } else { AddEnergy(wind.curStrength*0.5f); } } } AddEnergy(energyTickMake*0.5f); if(health<maxHealth) { health += unitDef->autoHeal; if(restTime > unitDef->idleTime) { health += unitDef->idleAutoHeal; } if(health>maxHealth) health=maxHealth; } bonusShieldSaved+=0.05f; residualImpulse*=0.6; if(wantCloak) { if(helper->GetClosestEnemyUnitNoLosTest(pos,unitDef->decloakDistance,allyteam)) { curCloakTimeout=gs->frameNum+cloakTimeout; isCloaked=false; } if(isCloaked || gs->frameNum>=curCloakTimeout) { float cloakCost=unitDef->cloakCost; if(speed.SqLength()>0.2) cloakCost=unitDef->cloakCostMoving; if(UseEnergy(cloakCost * 0.5f)) { isCloaked=true; } else { isCloaked=false; } } else { isCloaked=false; } } else { isCloaked=false; } if(uh->waterDamage && (physicalState==CSolidObject::Floating || (physicalState==CSolidObject::OnGround && pos.y<=-3 && readmap->mipHeightmap[1][int((pos.z/(SQUARE_SIZE*2))*gs->hmapx+(pos.x/(SQUARE_SIZE*2)))]<-1))) { DoDamage(DamageArray()*uh->waterDamage,0,ZeroVector); } if(unitDef->canKamikaze) { if(fireState==2) { CUnit* u=helper->GetClosestEnemyUnitNoLosTest(pos,unitDef->kamikazeDist,allyteam); if(u && u->physicalState!=CSolidObject::Flying && u->speed.dot(pos - u->pos)<=0) //self destruct when unit start moving away from mine, should maximize damage KillUnit(true,false,0); } if(userTarget && userTarget->pos.distance(pos)<unitDef->kamikazeDist) KillUnit(true,false,0); if(userAttackGround && userAttackPos.distance(pos)<unitDef->kamikazeDist) KillUnit(true,false,0); } if(!weapons.empty()) { haveTarget=false; haveUserTarget=false; //aircraft does not want this if (moveType->useHeading) { frontdir=GetVectorFromHeading(heading); if(upright || !unitDef->canmove) { updir=UpVector; rightdir=frontdir.cross(updir); } else { updir=ground->GetNormal(pos.x,pos.z); rightdir=frontdir.cross(updir); rightdir.Normalize(); frontdir=updir.cross(rightdir); } } if(!dontFire) { for(vector<CWeapon*>::iterator wi=weapons.begin(); wi!=weapons.end(); ++wi) { CWeapon* w=*wi; if(userTarget && !w->haveUserTarget && (haveDGunRequest || !unitDef->canDGun || !w->weaponDef->manualfire)) w->AttackUnit(userTarget,true); else if(userAttackGround && !w->haveUserTarget && (haveDGunRequest || !unitDef->canDGun || !w->weaponDef->manualfire)) w->AttackGround(userAttackPos,true); w->SlowUpdate(); if(w->targetType==Target_None && fireState>0 && lastAttacker && lastAttack+200>gs->frameNum) w->AttackUnit(lastAttacker,false); } } } if(moveType->progressState == CMoveType::Active) { if(/*physicalState == OnGround*/seismicSignature && !(losStatus[gu->myAllyTeam] & LOS_INLOS) && radarhandler->InSeismicDistance(this, gu->myAllyTeam)) new CSimpleGroundFlash(pos + float3(radarhandler->radarErrorSize[gu->myAllyTeam]*(0.5f-gu->usRandFloat()),0,radarhandler->radarErrorSize[gu->myAllyTeam]*(0.5f-gu->usRandFloat())), ph->seismictex, 30, 15, 0, seismicSignature, 1, float3(0.8,0.0,0.0)); } CalculateTerrainType(); UpdateTerrainType(); }
int BrigadeClass::MoveUnit (CampaignTime time) { Unit e; int en,me,be,te,toorder,role; F4PFList nearlist = NULL; Objective o; // Check if we have a valid objective o = GetUnitObjective(); if (!o || !TeamInfo[GetTeam()]->gtm->IsValidObjective(GetOrders(),o)) { if (o && (GetOrders() == GORD_CAPTURE || GetOrders() == GORD_ASSAULT || GetOrders() == GORD_AIRBORNE)) SetUnitOrders(GORD_SECURE,o->Id()); else { o = FindRetreatPath(this,3,FIND_SECONDARYONLY); if (!o) { // We've been cut off - surrender? CheckForSurrender(); return -1; } SetUnitOrders(GORD_RESERVE,o->Id()); } } // Check if we have elements requesting orders role = GetUnitCurrentRole(); toorder = te = 0; e = GetFirstUnitElement(); while (e) { te++; if (!e->Assigned()) toorder++; e = GetNextUnitElement(); } if (!te) { KillUnit(); return 0; } // Support brigades just update their position and return if (FindUnitSupportRole(this)) { UpdateParentStatistics(); return 0; } // Check to make sure our orders are still valid. // if (!CheckTactic(GetUnitTactic())) ChooseTactic(); // Upon new orders, reset our element's ordered flags && collect list of possible positions if (Ordered() || toorder) { Objective o; o = GetUnitObjective(); if (role == GRO_ATTACK) nearlist = GetChildObjectives(o, MAXLINKS_FROM_SO_OFFENSIVE, FIND_STANDARDONLY); else nearlist = GetChildObjectives(o, MAXLINKS_FROM_SO_DEFENSIVE, FIND_STANDARDONLY); // Eliminate any objectives we've previously been unable to find a path to // Clear all but attack orders (once we attack, we only stop when we break) e = GetFirstUnitElement(); while (e) { if (!e->Broken() && !e->Engaged() && e->Assigned() && e->GetUnitCurrentRole() != GRO_ATTACK) { e->SetAssigned(0); toorder++; } else if (e->Assigned() && !OnValidObjective(e, e->GetUnitCurrentRole(), nearlist)) { e->SetAssigned(0); toorder++; } e = GetNextUnitElement(); } // Loop in here until all our elements are assigned while (toorder) { // Order elements e = GetFirstUnitElement(); while (e) { if (!e->Assigned()) OrderElement(e, nearlist); e = GetNextUnitElement(); } // Check for pre-empted elements for (en=toorder=0; en<te; en++) { e = GetUnitElement(en); if (e && !e->Assigned()) toorder++; } } if (nearlist) { nearlist->DeInit(); delete nearlist; nearlist = NULL; } } // Make sure at least somebody is doing our job for (me=be=en=0; en<te; en++) { e = GetUnitElement(en); if (e) { if (e->Broken()) { be++; } else if (e->GetUnitCurrentRole() == role) { me++; } } } // Check for broken status if (be > me) SetBroken(1); // Check if we're still valid to perform our orders if (!me) { if (role == GRO_ATTACK) SetOrders (GORD_DEFEND); // Switch to defense orders else if (GetOrders() != GORD_RESERVE) SetUnitObjective(FalconNullId); // We'll pick a reserve location next time through } UpdateParentStatistics(); return 0; }
bool CUnit::AddBuildPower(float amount, CUnit* builder) { if (amount > 0.0f) { // build / repair if (!beingBuilt && (health >= maxHealth)) { return false; } lastNanoAdd = gs->frameNum; const float part = amount / buildTime; if (beingBuilt) { const float metalUse = (metalCost * part); const float energyUse = (energyCost * part); if ((gs->Team(builder->team)->metal >= metalUse) && (gs->Team(builder->team)->energy >= energyUse)) { builder->UseMetal(metalUse); builder->UseEnergy(energyUse); health += (maxHealth * part); buildProgress += part; if (buildProgress >= 1.0f) { if (health > maxHealth) { health = maxHealth; } FinishedBuilding(); } return true; } else { // update the energy and metal required counts gs->Team(builder->team)->metalPull += metalUse; gs->Team(builder->team)->energyPull += energyUse; } return false; } else { if (health < maxHealth) { health += maxHealth * part; if (health > maxHealth) { health = maxHealth; } return true; } return false; } } else { // reclaim if(isDead) return false; restTime=0; float part=amount/buildTime; health+=maxHealth*part; if(beingBuilt){ builder->AddMetal(metalCost*-part); buildProgress+=part; if(buildProgress<0 || health<0){ KillUnit(false,true,0); return false; } } else { if(health<0){ builder->AddMetal(metalCost); KillUnit(false,true,0); return false; } } return true; } return false; }