Beispiel #1
0
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;
}
Beispiel #2
0
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;
	}
Beispiel #5
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;
}
Beispiel #6
0
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
}
Beispiel #7
0
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;
	}
Beispiel #9
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;
}