Exemple #1
0
void CScriptMoveType::TrackSlope()
{
	owner->frontdir = GetVectorFromHeading(owner->heading);
	owner->updir = ground->GetSmoothNormal(owner->pos.x, owner->pos.z);
	owner->rightdir = owner->frontdir.cross(owner->updir);
	owner->rightdir.Normalize();
	owner->frontdir = owner->updir.cross(owner->rightdir);
}
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);
	}
}
Exemple #3
0
void CFeature::CalculateTransform()
{
	updir    = (!def->upright)? ground->GetNormal(pos.x, pos.z): UpVector;
	frontdir = GetVectorFromHeading(heading);
	rightdir = (frontdir.cross(updir)).Normalize();
	frontdir = (updir.cross(rightdir)).Normalize();

	transMatrix = CMatrix44f(pos, -rightdir, updir, frontdir);
}
Exemple #4
0
void CScriptMoveType::SetHeading(short heading)
{
	owner->heading = heading;
	if (!trackSlope) {
		owner->frontdir = GetVectorFromHeading(heading);
		owner->updir = UpVector;
		owner->rightdir = owner->frontdir.cross(UpVector);
	}
}
Exemple #5
0
void CBuilding::ForcedMove(const float3& newPos, int facing) {
	buildFacing = facing;
	pos = helper->Pos2BuildPos(BuildInfo(unitDef, newPos, buildFacing));
	speed = ZeroVector;
	heading = GetHeadingFromFacing(buildFacing);
	frontdir = GetVectorFromHeading(heading);
	CUnit::ForcedMove(pos);
	unitLoader.FlattenGround(this);
}
Exemple #6
0
void CBuilding::ForcedMove(const float3& newPos) {
	heading = GetHeadingFromFacing(buildFacing);
	frontdir = GetVectorFromHeading(heading);

	SetVelocity(ZeroVector);
	Move(CGameHelper::Pos2BuildPos(BuildInfo(unitDef, newPos, buildFacing), true), false);
	UpdateMidAndAimPos();

	CUnit::ForcedMove(pos);

	unitLoader->FlattenGround(this);
}
Exemple #7
0
void CFeature::ForcedSpin(const float3& newDir)
{
	float3 updir = UpVector;
	if (updir == newDir) {
		//FIXME perhaps save the old right,up,front directions, so we can
		// reconstruct the old upvector and generate a better assumption for updir
		updir -= GetVectorFromHeading(heading);
	}
	float3 rightdir = newDir.cross(updir).Normalize();
	updir = rightdir.cross(newDir);
	transMatrix = CMatrix44f(pos, -rightdir, updir, newDir);
	heading = GetHeadingFromVector(newDir.x, newDir.z);
}
void CFeature::CalculateTransform ()
{
	float3 frontDir=GetVectorFromHeading(heading);
	float3 upDir;

	if (def->upright) upDir = float3(0.0f,1.0f,0.0f);
	else upDir = ground->GetNormal(pos.x,pos.z);

	float3 rightDir=frontDir.cross(upDir);
	rightDir.Normalize();
	frontDir=upDir.cross(rightDir);
	frontDir.Normalize ();

	transMatrix = CMatrix44f (pos,-rightDir,upDir,frontDir);
}
Exemple #9
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, unit);
	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;

}
Exemple #10
0
void CTAAirMoveType::UpdateBanking(bool noBanking)
{
    SyncedFloat3 &frontdir = owner->frontdir;
    SyncedFloat3 &updir = owner->updir;

    if (!owner->upright) {
        float wantedPitch = 0;

        if (aircraftState == AIRCRAFT_FLYING && flyState == FLY_ATTACKING && circlingPos.y < owner->pos.y) {
            wantedPitch = (circlingPos.y - owner->pos.y) / circlingPos.distance(owner->pos);
        }

        currentPitch = currentPitch * 0.95f + wantedPitch * 0.05f;
    }

    frontdir = GetVectorFromHeading(owner->heading);
    frontdir.y = currentPitch;
    frontdir.Normalize();

    float3 rightdir(frontdir.cross(UpVector));		//temp rightdir
    rightdir.Normalize();

    float wantedBank = 0.0f;
    if (!noBanking && bankingAllowed) wantedBank = rightdir.dot(deltaSpeed)/accRate*0.5f;

    const float limit = std::min(1.0f,goalPos.SqDistance2D(owner->pos)*Square(0.15f));
    if (Square(wantedBank) > limit) {
        wantedBank =  math::sqrt(limit);
    } else if (Square(wantedBank) < -limit) {
        wantedBank = -math::sqrt(limit);
    }

    //Adjust our banking to the desired value
    if (currentBank > wantedBank) {
        currentBank -= std::min(0.03f, currentBank - wantedBank);
    } else {
        currentBank += std::min(0.03f, wantedBank - currentBank);
    }

    // Calculate a suitable upvector
    updir = rightdir.cross(frontdir);
    updir = updir * cos(currentBank) + rightdir * sin(currentBank);
    owner->rightdir = frontdir.cross(updir);
}
Exemple #11
0
void CFeature::ForcedSpin(const float3& newDir)
{
/*
	heading = GetHeadingFromVector(newDir.x, newDir.z);
	CalculateTransform();
	if (def->drawType >= DRAWTYPE_TREE) {
		treeDrawer->DeleteTree(pos);
		treeDrawer->AddTree(def->drawType - 1, pos, 1.0f);
	}
*/

	float3 updir = UpVector;
	if (updir == newDir) {
		//FIXME perhaps save the old right,up,front directions, so we can
		// reconstruct the old upvector and generate a better assumption for updir
		updir -= GetVectorFromHeading(heading);
	}
	float3 rightdir = newDir.cross(updir).Normalize();
	updir = rightdir.cross(newDir);
	transMatrix = CMatrix44f(pos, -rightdir, updir, newDir);
	heading = GetHeadingFromVector(newDir.x, newDir.z);
}
void CTAAirMoveType::UpdateBanking(bool noBanking)
{
	float3 &frontdir = owner->frontdir;
	float3 &updir = owner->updir;

	float wantedPitch=0;
	if(aircraftState==AIRCRAFT_FLYING && flyState==FLY_ATTACKING && circlingPos.y<owner->pos.y){
		wantedPitch=(circlingPos.y-owner->pos.y)/circlingPos.distance(owner->pos);
	}
	currentPitch=currentPitch*0.95+wantedPitch*0.05;

	frontdir = GetVectorFromHeading(owner->heading);
	frontdir.y=currentPitch;
	frontdir.Normalize();

	float3 rightdir(frontdir.cross(UpVector));		//temp rightdir
	rightdir.Normalize();

	float wantedBank = 0.0f;
	if (!noBanking) wantedBank = rightdir.dot(deltaSpeed)/accRate*0.5;

	float limit=min(1.0f,goalPos.distance2D(owner->pos)*0.15f);
	if(wantedBank>limit)
		wantedBank=limit;
	else if(wantedBank<-limit)
		wantedBank=-limit;

	//Adjust our banking to the desired value
	if (currentBank > wantedBank)
		currentBank -= min(0.03f, currentBank - wantedBank);
	else 
		currentBank += min(0.03f, wantedBank - currentBank);

	//Calculate a suitable upvector
	updir= rightdir.cross(frontdir);
	updir = updir*cos(currentBank)+rightdir*sin(currentBank);
	owner->rightdir = frontdir.cross(updir);
}
CUnit* CUnitLoader::LoadUnit(const string& name, float3 pos, int side, bool build, int facing)
{
	CUnit* unit;
START_TIME_PROFILE;

	UnitDef* ud= unitDefHandler->GetUnitByName(name);
	if(!ud)
		throw content_error("Couldn't find unittype " +  name);

	string type = ud->type;

	if(!build){
		pos.y=ground->GetHeight2(pos.x,pos.z);
		if(ud->floater && pos.y<0)
			pos.y = -ud->waterline;
	}
	bool blocking = false;	//Used to tell if ground area shall be blocked of not.

	//unit = new CUnit(pos, side);
	if (side < 0)
		side = MAX_TEAMS-1;

	if(type=="GroundUnit"){
		unit=new CUnit;
		blocking = true;
	} else if (type=="Transport"){
		unit=new CTransportUnit;
		blocking = true;
	} else if (type=="Building"){
		unit=new CBuilding;
		blocking = true;
	} else if (type=="Factory"){
		unit=new CFactory;
		blocking = true;
	} else if (type=="Builder"){
		unit=new CBuilder;
		blocking = true;
	} else if (type=="Bomber" || type=="Fighter"){
		unit=new CUnit;
	} else if (type == "MetalExtractor") {
		unit = new CExtractorBuilding;
		blocking = true;
	} else {
		logOutput << "Unknown unit type " << type.c_str() << "\n";
		return 0;
	}

	unit->UnitInit (ud, side, pos);

	unit->beingBuilt=build;

	unit->xsize = (facing&1)==0 ? ud->xsize : ud->ysize;
	unit->ysize = (facing&1)==1 ? ud->xsize : ud->ysize;
	unit->buildFacing = facing;
	unit->power=ud->power;
	unit->maxHealth=ud->health;
	unit->health=ud->health;
	//unit->metalUpkeep=ud->metalUpkeep*16.0f/GAME_SPEED;
	//unit->energyUpkeep=ud->energyUpkeep*16.0f/GAME_SPEED;
	unit->controlRadius=(int)(ud->controlRadius/SQUARE_SIZE);
	unit->losHeight=ud->losHeight;
	unit->metalCost=ud->metalCost;
	unit->energyCost=ud->energyCost;
	unit->buildTime=ud->buildTime;
	unit->aihint=ud->aihint;
	unit->tooltip=ud->humanName + " " + ud->tooltip;
	unit->armoredMultiple=max(0.0001f,ud->armoredMultiple);		//armored multiple of 0 will crash spring
	unit->wreckName=ud->wreckName;
	unit->realLosRadius=(int) (ud->losRadius);
	unit->realAirLosRadius=(int) (ud->airLosRadius);
	unit->upright=ud->upright;
	unit->radarRadius=ud->radarRadius/(SQUARE_SIZE*8);
	unit->sonarRadius=ud->sonarRadius/(SQUARE_SIZE*8);
	unit->jammerRadius=ud->jammerRadius/(SQUARE_SIZE*8);
	unit->sonarJamRadius=ud->sonarJamRadius/(SQUARE_SIZE*8);
	unit->seismicRadius = ud->seismicRadius /(SQUARE_SIZE*8);
	unit->seismicSignature = ud->seismicSignature;
	unit->hasRadarCapacity=unit->radarRadius || unit->sonarRadius || unit->jammerRadius || unit->sonarJamRadius || unit->seismicRadius;
	unit->stealth=ud->stealth;
	unit->category=ud->category;
	unit->armorType=ud->armorType;
	unit->floatOnWater = ud->floater || (ud->movedata && ((ud->movedata->moveType == MoveData::Hover_Move) || (ud->movedata->moveType == MoveData::Ship_Move)));
	unit->maxSpeed = ud->speed/30.0;

	if(ud->highTrajectoryType==1)
		unit->useHighTrajectory=true;
		
	if(ud->noAutoFire)
		unit->fireState=0;

	if(build){
		unit->ChangeLos(1,1);
		unit->health=0.1f;
	} else {
		unit->ChangeLos((int)(ud->losRadius),(int)(ud->airLosRadius));
	}

	if(type=="GroundUnit"){
		new CMobileCAI(unit);
	} else if(type=="Transport"){
		new CTransportCAI(unit);
	} else if(type=="Factory"){
		new CFactoryCAI(unit);
	} else if(type=="Builder"){
		new CBuilderCAI(unit);
	} else if(type=="Bomber"){
		if (ud->hoverAttack)
			new CMobileCAI(unit);
		else
			new CAirCAI(unit);
	} else if(type=="Fighter"){
		if (ud->hoverAttack)
			new CMobileCAI(unit);
		else
			new CAirCAI(unit);
	} else {
		new CCommandAI(unit);
	}

	if(ud->canmove && !ud->canfly && type!="Factory"){
		CGroundMoveType* mt=new CGroundMoveType(unit);
		mt->maxSpeed=ud->speed/GAME_SPEED;
		mt->maxWantedSpeed=ud->speed/GAME_SPEED;
		mt->turnRate=ud->turnRate;
		mt->baseTurnRate=ud->turnRate;
		if (!mt->accRate) 
			logOutput << "acceleration of " << ud->name.c_str() << " is zero!!\n";
		mt->moveType=ud->moveType;
		mt->accRate=ud->maxAcc;
		mt->floatOnWater=ud->movedata->moveType==MoveData::Hover_Move || ud->movedata->moveType==MoveData::Ship_Move;
		if(!unit->beingBuilt)
			unit->mass=ud->mass;	//otherwise set this when finished building instead
		unit->moveType=mt;


		//Ground-mobility
		unit->mobility = new CMobility();
		unit->mobility->canFly = false;
		unit->mobility->subMarine = false;		//Not always correct, as submarines are treated as ships.
		unit->mobility->maxAcceleration = ud->maxAcc;
		unit->mobility->maxBreaking = -3*ud->maxAcc;
		unit->mobility->maxSpeed = ud->speed / GAME_SPEED;
		unit->mobility->maxTurnRate = (short int) ud->turnRate;
		unit->mobility->moveData = ud->movedata;

	} else if(ud->canfly){
		//Air-mobility
		unit->mobility = new CMobility();
		unit->mobility->canFly = true;
		unit->mobility->subMarine = false;
		unit->mobility->maxAcceleration = ud->maxAcc;
		unit->mobility->maxBreaking = -3*ud->maxAcc;	//Correct?
		unit->mobility->maxSpeed = ud->speed / GAME_SPEED;
		unit->mobility->maxTurnRate = (short int) ud->turnRate;
		unit->mobility->moveData = ud->movedata;

		if(!unit->beingBuilt)
			unit->mass=ud->mass; //otherwise set this when finished building instead

		if ((type == "Builder") || ud->hoverAttack || ud->transportCapacity) {
			CTAAirMoveType *mt = new CTAAirMoveType(unit);

			mt->turnRate = ud->turnRate;
			mt->maxSpeed = ud->speed / GAME_SPEED;
			mt->accRate = ud->maxAcc;
			mt->decRate = ud->maxDec;
			mt->wantedHeight = ud->wantedHeight+gs->randFloat()*5;
			mt->orgWantedHeight=mt->wantedHeight;
			mt->dontLand = ud->DontLand ();

			unit->moveType = mt;
		}
		else {
			CAirMoveType *mt = new CAirMoveType(unit);
		
			if(type=="Fighter")
				mt->isFighter=true;

			mt->wingAngle = ud->wingAngle;
			mt->invDrag = 1 - ud->drag;
			mt->frontToSpeed = ud->frontToSpeed;
			mt->speedToFront = ud->speedToFront;
			mt->myGravity = ud->myGravity;

			mt->maxBank = ud->maxBank;
			mt->maxPitch = ud->maxPitch;
			mt->turnRadius = ud->turnRadius;
			mt->wantedHeight = ud->wantedHeight*1.5f+(gs->randFloat()-0.3f)*15*(mt->isFighter?2:1);;

			mt->maxAcc = ud->maxAcc;
			mt->maxAileron = ud->maxAileron;
			mt->maxElevator = ud->maxElevator;
			mt->maxRudder = ud->maxRudder;

			unit->moveType = mt;
		}
	} else {
		unit->moveType=new CMoveType(unit);
		unit->upright=true;
	}

	unit->energyTickMake = ud->energyMake;
	if(ud->tidalGenerator>0)
		unit->energyTickMake += ud->tidalGenerator*readmap->tidalStrength;


//	if(!ud->weapons.empty())
//		unit->mainDamageType=unit->weapons.front()->damageType;

	//unit->model=unitModelLoader->GetModel(ud->model.modelname,side);
	unit->model = modelParser->Load3DO((ud->model.modelpath).c_str(),ud->canfly?0.5f:1,side); 	//this is a hack to make aircrafts less likely to collide and get hit by nontracking weapons
	unit->SetRadius(unit->model->radius);

	if(ud->floater)
		unit->pos.y = max(-ud->waterline,ground->GetHeight2(unit->pos.x,unit->pos.z));
	else
		unit->pos.y=ground->GetHeight2(unit->pos.x,unit->pos.z);
	//unit->pos.y=ground->GetHeight(unit->pos.x,unit->pos.z);

	unit->cob = new CCobInstance(GCobEngine.GetCobFile("scripts/" + name+".cob"), unit);
	unit->localmodel = modelParser->CreateLocalModel(unit->model, &unit->cob->pieces);

	for(unsigned int i=0; i< ud->weapons.size(); i++)
		unit->weapons.push_back(LoadWeapon(ud->weapons[i].def,unit,&ud->weapons[i]));
	
	// Calculate the max() of the available weapon reloadtimes
	int relMax = 0;
	for (vector<CWeapon*>::iterator i = unit->weapons.begin(); i != unit->weapons.end(); ++i) {
		if ((*i)->reloadTime > relMax)
			relMax = (*i)->reloadTime;
		if(dynamic_cast<CBeamLaser*>(*i))
			relMax=150;
	}
	relMax *= 30;		// convert ticks to milliseconds

	// TA does some special handling depending on weapon count
	if (unit->weapons.size() > 1)
		relMax = max(relMax, 3000);

	// Call initializing script functions
	unit->cob->Call(COBFN_Create);
	unit->cob->Call("SetMaxReloadTime", relMax);

	unit->heading = facing*16*1024;
	unit->frontdir=GetVectorFromHeading(unit->heading);
	unit->updir=UpVector;
	unit->rightdir=unit->frontdir.cross(unit->updir);
	unit->Init();

	unit->yardMap = ud->yardmaps[facing];

	if(!build)
		unit->FinishedBuilding();

END_TIME_PROFILE("Unit loader");
	return unit;
}
Exemple #14
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();
}
Exemple #15
0
void CUnit::Draw()
{
    glPushMatrix();
    float3 interPos=pos+speed*gu->timeOffset;

    if (physicalState == Flying && unitDef->canmove) {
        //aircraft or skidding ground unit
        CMatrix44f transMatrix(interPos,-rightdir,updir,frontdir);

        glMultMatrixf(&transMatrix[0]);
    } else if(upright || !unitDef->canmove) {
        glTranslatef3(interPos);
        if(heading!=0)
            glRotatef(heading*(180.0/32768.0),0,1,0);
    } else {
        float3 frontDir=GetVectorFromHeading(heading);		//making local copies of vectors
        float3 upDir=ground->GetSmoothNormal(pos.x,pos.z);
        float3 rightDir=frontDir.cross(upDir);
        rightDir.Normalize();
        frontDir=upDir.cross(rightDir);

        CMatrix44f transMatrix(interPos,-rightDir,upDir,frontDir);

        glMultMatrixf(&transMatrix[0]);
    }

    if(beingBuilt && unitDef->showNanoFrame) {
        if(shadowHandler->inShadowPass) {
            if(buildProgress>0.66)
                localmodel->Draw();
        } else {
            float height=model->height;
            float start=model->miny;
            glEnable(GL_CLIP_PLANE0);
            glEnable(GL_CLIP_PLANE1);
            //float col=fabs(128.0-((gs->frameNum*4)&255))/255.0+0.5f;
            float3 fc;// fc frame color
            if(gu->teamNanospray) {
                unsigned char* tcol=gs->Team(team)->color;
                fc = float3(tcol[0]*(1./255.),tcol[1]*(1./255.),tcol[2]*(1./255.));
            } else {
                fc = unitDef->nanoColor;
            }
            glColorf3(fc);

            unitDrawer->UnitDrawingTexturesOff(model);

            double plane[4]= {0,-1,0,start+height*buildProgress*3};
            glClipPlane(GL_CLIP_PLANE0 ,plane);
            double plane2[4]= {0,1,0,-start-height*(buildProgress*10-9)};
            glClipPlane(GL_CLIP_PLANE1 ,plane2);
            glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
            localmodel->Draw();
            glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);

            if(buildProgress>0.33) {
                glColorf3(fc*1.4f);
                double plane[4]= {0,-1,0,start+height*(buildProgress*3-1)};
                glClipPlane(GL_CLIP_PLANE0 ,plane);
                double plane2[4]= {0,1,0,-start-height*(buildProgress*3-2)};
                glClipPlane(GL_CLIP_PLANE1 ,plane2);

                localmodel->Draw();
            }
            glDisable(GL_CLIP_PLANE1);
            unitDrawer->UnitDrawingTexturesOn(model);

            if(buildProgress>0.66) {
                double plane[4]= {0,-1,0,start+height*(buildProgress*3-2)};
                glClipPlane(GL_CLIP_PLANE0 ,plane);
                if(shadowHandler->drawShadows && !water->drawReflection) {
                    glPolygonOffset(1,1);
                    glEnable(GL_POLYGON_OFFSET_FILL);
                }
                localmodel->Draw();
                if(shadowHandler->drawShadows && !water->drawReflection) {
                    glDisable(GL_POLYGON_OFFSET_FILL);
                }
            }
            glDisable(GL_CLIP_PLANE0);
        }
    } else {
        localmodel->Draw();
    }
    if(gu->drawdebug) {
        glPushMatrix();
        glTranslatef3(frontdir*relMidPos.z + updir*relMidPos.y + rightdir*relMidPos.x);
        GLUquadricObj* q=gluNewQuadric();
        gluQuadricDrawStyle(q,GLU_LINE);
        gluSphere(q,radius,10,10);
        gluDeleteQuadric(q);
        glPopMatrix();
    }/**/
    glPopMatrix();
}
Exemple #16
0
CUnit* CUnitLoader::LoadUnit(const UnitDef* ud, float3 pos, int team,
                             bool build, int facing, const CUnit* builder)
{
	GML_RECMUTEX_LOCK(sel); // LoadUnit - for anti deadlock purposes.
	GML_RECMUTEX_LOCK(quad); // LoadUnit - make sure other threads cannot access an incomplete unit

	SCOPED_TIMER("Unit loader");

	CUnit* unit;

	std::string type = ud->type;

	// clamp to map
	if (pos.x < 0)
		pos.x = 0;
	if (pos.x >= gs->mapx * SQUARE_SIZE)
		pos.x = gs->mapx-1;
	if (pos.z < 0)
		pos.z = 0;
	if (pos.z >= gs->mapy * SQUARE_SIZE)
		pos.z = gs->mapy-1;

	if (!build) {
		pos.y = ground->GetHeight2(pos.x, pos.z);
		if (ud->floater && pos.y < 0.0f) {
			// adjust to waterline iif we are submerged
 			pos.y = -ud->waterline;
		}
	}

	if (team < 0) {
		team = teamHandler->GaiaTeamID(); // FIXME use gs->gaiaTeamID ?  (once it is always enabled)
		if (team < 0)
			throw content_error("Invalid team and no gaia team to put unit in");
	}

	if (type == "GroundUnit") {
		unit = new CUnit;
	} else if (type == "Transport") {
		unit = new CTransportUnit;
	} else if (type == "Building") {
		unit = new CBuilding;
	} else if (type == "Factory") {
		unit = new CFactory;
	} else if (type == "Builder") {
		unit = new CBuilder;
	} else if (type == "Bomber" || type == "Fighter") {
		unit = new CUnit;
	} else if (type == "MetalExtractor") {
		unit = new CExtractorBuilding;
	} else {
		LogObject() << "Unknown unit type " << type.c_str() << "\n";
		return NULL;
	}

	unit->UnitInit(ud, team, pos);
	unit->beingBuilt = build;

	unit->buildFacing = abs(facing) % 4;
	unit->xsize = ((unit->buildFacing & 1) == 0) ? ud->xsize : ud->zsize;
	unit->zsize = ((unit->buildFacing & 1) == 1) ? ud->xsize : ud->zsize;

	unit->power = ud->power;
	unit->maxHealth = ud->health;
	unit->health = ud->health;
	//unit->metalUpkeep = ud->metalUpkeep*16.0f/GAME_SPEED;
	//unit->energyUpkeep = ud->energyUpkeep*16.0f/GAME_SPEED;
	unit->controlRadius = (int)(ud->controlRadius / SQUARE_SIZE);
	unit->losHeight = ud->losHeight;
	unit->metalCost = ud->metalCost;
	unit->energyCost = ud->energyCost;
	unit->buildTime = ud->buildTime;
	unit->aihint = ud->aihint;
	unit->tooltip = ud->humanName + " - " + ud->tooltip;
	unit->armoredMultiple = std::max(0.0001f, ud->armoredMultiple);		//armored multiple of 0 will crash spring
	unit->wreckName = ud->wreckName;

	unit->realLosRadius = (int) (ud->losRadius);
	unit->realAirLosRadius = (int) (ud->airLosRadius);
	unit->upright = ud->upright;
	unit->radarRadius      = ud->radarRadius    / (SQUARE_SIZE * 8);
	unit->sonarRadius      = ud->sonarRadius    / (SQUARE_SIZE * 8);
	unit->jammerRadius     = ud->jammerRadius   / (SQUARE_SIZE * 8);
	unit->sonarJamRadius   = ud->sonarJamRadius / (SQUARE_SIZE * 8);
	unit->seismicRadius    = ud->seismicRadius  / (SQUARE_SIZE * 8);
	unit->seismicSignature = ud->seismicSignature;
	unit->hasRadarCapacity = unit->radarRadius  || unit->sonarRadius    ||
	                         unit->jammerRadius || unit->sonarJamRadius ||
	                         unit->seismicRadius;
	unit->stealth = ud->stealth;
	unit->sonarStealth = ud->sonarStealth;
	unit->category = ud->category;
	unit->armorType = ud->armorType;
	unit->floatOnWater =
		ud->floater || (ud->movedata && ((ud->movedata->moveType == MoveData::Hover_Move) ||
		                                 (ud->movedata->moveType == MoveData::Ship_Move)));
	unit->maxSpeed = ud->speed / GAME_SPEED;
	unit->decloakDistance = ud->decloakDistance;

	unit->flankingBonusMode        = ud->flankingBonusMode;
	unit->flankingBonusDir         = ud->flankingBonusDir;
	unit->flankingBonusMobility    = ud->flankingBonusMobilityAdd * 1000;
	unit->flankingBonusMobilityAdd = ud->flankingBonusMobilityAdd;
	unit->flankingBonusAvgDamage = (ud->flankingBonusMax + ud->flankingBonusMin) * 0.5f;
	unit->flankingBonusDifDamage = (ud->flankingBonusMax - ud->flankingBonusMin) * 0.5f;


	if(ud->highTrajectoryType==1)
		unit->useHighTrajectory=true;

	if(ud->fireState >= 0)
		unit->fireState = ud->fireState;

	if(build){
		unit->ChangeLos(1,1);
		unit->health=0.1f;
	} else {
		unit->ChangeLos((int)(ud->losRadius),(int)(ud->airLosRadius));
	}

	if (type == "GroundUnit") {
		new CMobileCAI(unit);
	}
	else if (type == "Transport") {
		new CTransportCAI(unit);
	}
	else if (type == "Factory") {
		new CFactoryCAI(unit);
	}
	else if (type == "Builder") {
		new CBuilderCAI(unit);
	}
	else if (type == "Bomber") {
		if (ud->hoverAttack) {
			new CMobileCAI(unit);
		} else {
			new CAirCAI(unit);
		}
	}
	else if(type == "Fighter"){
		if (ud->hoverAttack) {
			new CMobileCAI(unit);
		} else {
			new CAirCAI(unit);
		}
	}
	else {
		new CCommandAI(unit);
	}

	if (ud->canmove && !ud->canfly && (type != "Factory")) {
		CGroundMoveType* mt = new CGroundMoveType(unit);
		mt->maxSpeed = ud->speed / GAME_SPEED;
		mt->maxWantedSpeed = ud->speed / GAME_SPEED;
		mt->turnRate = ud->turnRate;
		mt->baseTurnRate = ud->turnRate;

		if (mt->accRate <= 0.0f) {
			LogObject() << "acceleration of unit-type " << ud->name.c_str() << " is zero or negative!\n";
			mt->accRate = 0.01f;
		}

		mt->accRate = ud->maxAcc;
		mt->decRate = ud->maxDec;
		mt->floatOnWater = (ud->movedata->moveType == MoveData::Hover_Move ||
		                    ud->movedata->moveType == MoveData::Ship_Move);

		if (!unit->beingBuilt) {
			// otherwise set this when finished building instead
			unit->mass = ud->mass;
		}
		unit->moveType = mt;

		// Ground-mobility
		unit->mobility = new MoveData(ud->movedata);

	} else if (ud->canfly) {
		// Air-mobility
		unit->mobility = new MoveData(ud->movedata);

		if (!unit->beingBuilt) {
			// otherwise set this when finished building instead
			unit->mass = ud->mass;
		}

		if ((type == "Builder") || ud->hoverAttack || ud->transportCapacity) {
			CTAAirMoveType* mt = new CTAAirMoveType(unit);

			mt->turnRate = ud->turnRate;
			mt->maxSpeed = ud->speed / GAME_SPEED;
			mt->accRate = ud->maxAcc;
			mt->decRate = ud->maxDec;
			mt->wantedHeight = ud->wantedHeight + gs->randFloat() * 5;
			mt->orgWantedHeight = mt->wantedHeight;
			mt->dontLand = ud->DontLand();
			mt->collide = ud->collide;
			mt->altitudeRate = ud->verticalSpeed;
			mt->bankingAllowed = ud->bankingAllowed;

			unit->moveType = mt;
		}
		else {
			CAirMoveType *mt = new CAirMoveType(unit);

			if(type=="Fighter")
				mt->isFighter=true;

			mt->collide = ud->collide;

			mt->wingAngle = ud->wingAngle;
			mt->crashDrag = 1 - ud->crashDrag;
			mt->invDrag = 1 - ud->drag;
			mt->frontToSpeed = ud->frontToSpeed;
			mt->speedToFront = ud->speedToFront;
			mt->myGravity = ud->myGravity;

			mt->maxBank = ud->maxBank;
			mt->maxPitch = ud->maxPitch;
			mt->turnRadius = ud->turnRadius;
			mt->wantedHeight = (ud->wantedHeight * 1.5f) +
			                   ((gs->randFloat() - 0.3f) * 15 * (mt->isFighter ? 2 : 1));

			mt->maxAcc = ud->maxAcc;
			mt->maxAileron = ud->maxAileron;
			mt->maxElevator = ud->maxElevator;
			mt->maxRudder = ud->maxRudder;

			unit->moveType = mt;
		}
	} else {
		unit->moveType = new CMoveType(unit);
		unit->upright = true;
	}

	unit->energyTickMake = ud->energyMake;

	if (ud->tidalGenerator > 0)
		unit->energyTickMake += ud->tidalGenerator * mapInfo->map.tidalStrength;


	unit->model = ud->LoadModel();
	unit->SetRadius(unit->model->radius);

	modelParser->CreateLocalModel(unit);


	// copy the UnitDef volume instance
	//
	// aircraft still get half-size spheres for coldet purposes
	// iif no custom volume is defined (unit->model->radius and
	// unit->radius themselves are no longer altered)
	unit->collisionVolume = new CollisionVolume(ud->collisionVolume, unit->model->radius * ((ud->canfly)? 0.5f: 1.0f));

	if (unit->model->radius <= 60.0f) {
		// the interval-based method fails too easily for units
		// with small default volumes, force use of raytracing
		unit->collisionVolume->SetTestType(COLVOL_TEST_CONT);
	}


	if (ud->floater) {
		// restrict our depth to our waterline
		unit->pos.y = std::max(-ud->waterline, ground->GetHeight2(unit->pos.x, unit->pos.z));
	} else {
		unit->pos.y = ground->GetHeight2(unit->pos.x, unit->pos.z);
	}

	unit->script = CUnitScriptFactory::CreateScript(ud->scriptPath, unit);

	unit->weapons.reserve(ud->weapons.size());
	for (unsigned int i = 0; i < ud->weapons.size(); i++) {
		unit->weapons.push_back(LoadWeapon(ud->weapons[i].def, unit, &ud->weapons[i]));
	}

	// Call initializing script functions
	unit->script->Create();

	unit->heading = GetHeadingFromFacing(facing);
	unit->frontdir = GetVectorFromHeading(unit->heading);
	unit->updir = UpVector;
	unit->rightdir = unit->frontdir.cross(unit->updir);

	unit->yardMap = ud->yardmaps[facing];

	unit->Init(builder);

	if (!build) {
		unit->FinishedBuilding();
	}
	return unit;
}
CUnit* CUnitLoader::LoadUnit(const string& name, float3 pos, int team,
                             bool build, int facing, const CUnit* builder)
{
//	GML_RECMUTEX_LOCK(unit); // LoadUnit. Unitinit puts unit in the quadfield and activeUnits -
	GML_RECMUTEX_LOCK(sel); // LoadUnit. For anti deadlock purposes.
	GML_RECMUTEX_LOCK(quad); // LoadUnit. - make sure other threads cannot access an incomplete unit

	CUnit* unit;

	SCOPED_TIMER("Unit loader");

	const UnitDef* ud = unitDefHandler->GetUnitByName(name);
	if (!ud) {
		throw content_error("Couldn't find unittype " +  name);
	}

	string type = ud->type;

	if (!build) {
		pos.y = ground->GetHeight2(pos.x, pos.z);
		if (ud->floater && pos.y < 0.0f) {
			// adjust to waterline iif we are submerged
 			pos.y = -ud->waterline;
		}
	}

	if (team < 0) {
		team = MAX_TEAMS - 1; // FIXME use gs->gaiaTeamID ?  (once it is always enabled)
	}

	if (type == "GroundUnit") {
		unit = SAFE_NEW CUnit;
	} else if (type == "Transport") {
		unit = SAFE_NEW CTransportUnit;
	} else if (type == "Building") {
		unit = SAFE_NEW CBuilding;
	} else if (type == "Factory") {
		unit = SAFE_NEW CFactory;
	} else if (type == "Builder") {
		unit = SAFE_NEW CBuilder;
	} else if (type == "Bomber" || type == "Fighter") {
		unit = SAFE_NEW CUnit;
	} else if (type == "MetalExtractor") {
		unit = SAFE_NEW CExtractorBuilding;
	} else {
		logOutput << "Unknown unit type " << type.c_str() << "\n";
		return NULL;
	}

	unit->UnitInit(ud, team, pos);

	unit->beingBuilt = build;

	unit->xsize = ((facing & 1) == 0) ? ud->xsize : ud->zsize;
	unit->zsize = ((facing & 1) == 1) ? ud->xsize : ud->zsize;
	unit->buildFacing = facing;
	unit->power = ud->power;
	unit->maxHealth = ud->health;
	unit->health = ud->health;
	//unit->metalUpkeep = ud->metalUpkeep*16.0f/GAME_SPEED;
	//unit->energyUpkeep = ud->energyUpkeep*16.0f/GAME_SPEED;
	unit->controlRadius = (int)(ud->controlRadius / SQUARE_SIZE);
	unit->losHeight = ud->losHeight;
	unit->metalCost = ud->metalCost;
	unit->energyCost = ud->energyCost;
	unit->buildTime = ud->buildTime;
	unit->aihint = ud->aihint;
	unit->tooltip = ud->humanName + " - " + ud->tooltip;
	unit->armoredMultiple = std::max(0.0001f, ud->armoredMultiple);		//armored multiple of 0 will crash spring
	unit->wreckName = ud->wreckName;

	unit->realLosRadius = (int) (ud->losRadius);
	unit->realAirLosRadius = (int) (ud->airLosRadius);
	unit->upright = ud->upright;
	unit->radarRadius      = ud->radarRadius    / (SQUARE_SIZE * 8);
	unit->sonarRadius      = ud->sonarRadius    / (SQUARE_SIZE * 8);
	unit->jammerRadius     = ud->jammerRadius   / (SQUARE_SIZE * 8);
	unit->sonarJamRadius   = ud->sonarJamRadius / (SQUARE_SIZE * 8);
	unit->seismicRadius    = ud->seismicRadius  / (SQUARE_SIZE * 8);
	unit->seismicSignature = ud->seismicSignature;
	unit->hasRadarCapacity = unit->radarRadius  || unit->sonarRadius    ||
	                         unit->jammerRadius || unit->sonarJamRadius ||
	                         unit->seismicRadius;
	unit->stealth = ud->stealth;
	unit->sonarStealth = ud->sonarStealth;
	unit->category = ud->category;
	unit->armorType = ud->armorType;
	unit->floatOnWater =
		ud->floater || (ud->movedata && ((ud->movedata->moveType == MoveData::Hover_Move) ||
		                                 (ud->movedata->moveType == MoveData::Ship_Move)));
	unit->maxSpeed = ud->speed / 30.0f;
	unit->decloakDistance = ud->decloakDistance;

	unit->flankingBonusMode        = ud->flankingBonusMode;
	unit->flankingBonusDir         = ud->flankingBonusDir;
	unit->flankingBonusMobility    = ud->flankingBonusMobilityAdd * 1000;
	unit->flankingBonusMobilityAdd = ud->flankingBonusMobilityAdd;
	unit->flankingBonusAvgDamage = (ud->flankingBonusMax + ud->flankingBonusMin) * 0.5f;
	unit->flankingBonusDifDamage = (ud->flankingBonusMax - ud->flankingBonusMin) * 0.5f;


	if(ud->highTrajectoryType==1)
		unit->useHighTrajectory=true;

	if(ud->fireState >= 0)
		unit->fireState = ud->fireState;

	if(build){
		unit->ChangeLos(1,1);
		unit->health=0.1f;
	} else {
		unit->ChangeLos((int)(ud->losRadius),(int)(ud->airLosRadius));
	}

	if (type == "GroundUnit") {
		SAFE_NEW CMobileCAI(unit);
	}
	else if (type == "Transport") {
		SAFE_NEW CTransportCAI(unit);
	}
	else if (type == "Factory") {
		SAFE_NEW CFactoryCAI(unit);
	}
	else if (type == "Builder") {
		SAFE_NEW CBuilderCAI(unit);
	}
	else if (type == "Bomber") {
		if (ud->hoverAttack) {
			SAFE_NEW CMobileCAI(unit);
		} else {
			SAFE_NEW CAirCAI(unit);
		}
	}
	else if(type == "Fighter"){
		if (ud->hoverAttack) {
			SAFE_NEW CMobileCAI(unit);
		} else {
			SAFE_NEW CAirCAI(unit);
		}
	}
	else {
		SAFE_NEW CCommandAI(unit);
	}

	if (ud->canmove && !ud->canfly && (type != "Factory")) {
		CGroundMoveType* mt = SAFE_NEW CGroundMoveType(unit);
		mt->maxSpeed = ud->speed / GAME_SPEED;
		mt->maxWantedSpeed = ud->speed / GAME_SPEED;
		mt->turnRate = ud->turnRate;
		mt->baseTurnRate = ud->turnRate;

		if (!mt->accRate) {
			logOutput << "acceleration of " << ud->name.c_str() << " is zero!!\n";
		}

		mt->moveType = ud->moveType;
		mt->accRate = ud->maxAcc;
		mt->decRate = ud->maxDec;
		mt->floatOnWater = (ud->movedata->moveType == MoveData::Hover_Move ||
		                    ud->movedata->moveType == MoveData::Ship_Move);

		if (!unit->beingBuilt) {
			// otherwise set this when finished building instead
			unit->mass = ud->mass;
		}
		unit->moveType = mt;

		// Ground-mobility
		unit->mobility = SAFE_NEW MoveData(ud->movedata, GAME_SPEED);

	} else if (ud->canfly) {
		// Air-mobility
		unit->mobility = SAFE_NEW MoveData(ud->movedata, GAME_SPEED);

		if (!unit->beingBuilt) {
			// otherwise set this when finished building instead
			unit->mass = ud->mass;
		}

		if ((type == "Builder") || ud->hoverAttack || ud->transportCapacity) {
			CTAAirMoveType* mt = SAFE_NEW CTAAirMoveType(unit);

			mt->turnRate = ud->turnRate;
			mt->maxSpeed = ud->speed / GAME_SPEED;
			mt->accRate = ud->maxAcc;
			mt->decRate = ud->maxDec;
			mt->wantedHeight = ud->wantedHeight + gs->randFloat() * 5;
			mt->orgWantedHeight = mt->wantedHeight;
			mt->dontLand = ud->DontLand();
			mt->collide = ud->collide;
			mt->altitudeRate = ud->verticalSpeed;
			mt->bankingAllowed = ud->bankingAllowed;

			unit->moveType = mt;
		}
		else {
			CAirMoveType *mt = SAFE_NEW CAirMoveType(unit);

			if(type=="Fighter")
				mt->isFighter=true;

			mt->collide = ud->collide;

			mt->wingAngle = ud->wingAngle;
			mt->crashDrag = 1 - ud->crashDrag;
			mt->invDrag = 1 - ud->drag;
			mt->frontToSpeed = ud->frontToSpeed;
			mt->speedToFront = ud->speedToFront;
			mt->myGravity = ud->myGravity;

			mt->maxBank = ud->maxBank;
			mt->maxPitch = ud->maxPitch;
			mt->turnRadius = ud->turnRadius;
			mt->wantedHeight = (ud->wantedHeight * 1.5f) +
			                   ((gs->randFloat() - 0.3f) * 15 * (mt->isFighter ? 2 : 1));

			mt->maxAcc = ud->maxAcc;
			mt->maxAileron = ud->maxAileron;
			mt->maxElevator = ud->maxElevator;
			mt->maxRudder = ud->maxRudder;

			unit->moveType = mt;
		}
	} else {
		unit->moveType = SAFE_NEW CMoveType(unit);
		unit->upright = true;
	}

	unit->energyTickMake = ud->energyMake;

	if (ud->tidalGenerator > 0)
		unit->energyTickMake += ud->tidalGenerator * mapInfo->map.tidalStrength;


	unit->model = LoadModel(ud);
	unit->SetRadius(unit->model->radius);

	// copy the UnitDef volume archetype data
	unit->collisionVolume = SAFE_NEW CollisionVolume(ud->collisionVolume);

	// if no "collisionVolumeScales" tag was defined in UnitDef,
	// the default scale for this volume will be a ZeroVector
	if (unit->collisionVolume->GetScale(COLVOL_AXIS_X) <= 1.0f &&
		unit->collisionVolume->GetScale(COLVOL_AXIS_Y) <= 1.0f &&
		unit->collisionVolume->GetScale(COLVOL_AXIS_Z) <= 1.0f) {
		// aircraft still get half-size spheres for coldet purposes
		// if no custom volume is defined (unit->model->radius and
		// unit->radius themselves are no longer altered)
		const float scaleFactor = (ud->canfly)? 0.5f: 1.0f;
		unit->collisionVolume->SetDefaultScale(unit->model->radius * scaleFactor);

		if (unit->collisionVolume->GetBoundingRadius() <= 30.0f) {
			// the interval-based method fails too easily for units
			// with small default volumes, force use of raytracing
			unit->collisionVolume->SetTestType(COLVOL_TEST_CONT);
		}
	}

	if (ud->floater) {
		// restrict our depth to our waterline
		unit->pos.y = std::max(-ud->waterline, ground->GetHeight2(unit->pos.x, unit->pos.z));
	} else {
		unit->pos.y = ground->GetHeight2(unit->pos.x, unit->pos.z);
	}

	modelParser->CreateLocalModel(unit);
	unit->cob = SAFE_NEW CCobInstance(GCobEngine.GetCobFile("scripts/" + ud->cobFilename), unit);

	unit->weapons.reserve(ud->weapons.size());
	for (unsigned int i = 0; i < ud->weapons.size(); i++) {
		unit->weapons.push_back(LoadWeapon(ud->weapons[i].def, unit, &ud->weapons[i]));
	}

	// Calculate the max() of the available weapon reloadtimes
	int relMax = 0;
	for (vector<CWeapon*>::iterator i = unit->weapons.begin(); i != unit->weapons.end(); ++i) {
		if ((*i)->reloadTime > relMax)
			relMax = (*i)->reloadTime;
		if (dynamic_cast<CBeamLaser*>(*i))
			relMax = 150;
	}

	// convert ticks to milliseconds
	relMax *= 30;

	// TA does some special handling depending on weapon count
	if (unit->weapons.size() > 1) {
		relMax = std::max(relMax, 3000);
	}

	// Call initializing script functions
	unit->cob->Call(COBFN_Create);
	unit->cob->Call("SetMaxReloadTime", relMax);

	unit->heading = GetHeadingFromFacing(facing);
	unit->frontdir = GetVectorFromHeading(unit->heading);
	unit->updir = UpVector;
	unit->rightdir = unit->frontdir.cross(unit->updir);

	unit->yardMap = ud->yardmaps[facing];

	unit->Init(builder);

	if (!build) {
		unit->FinishedBuilding();
	}
	return unit;
}