Exemple #1
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 side, bool build)
{
	CUnit* unit;
START_TIME_PROFILE;

	UnitDef* ud= unitDefHandler->GetUnitByName(name);
	if(!ud){
		char t[500];
		sprintf(t,"Couldnt find unittype %s",name.c_str());
		handleerror(0,t,"Error loading unit",0);
		exit(0);
	}
	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 {
		(*info) << "Unknown unit type " << type.c_str() << "\n";
		return 0;
	}

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

	unit->beingBuilt=build;
	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/(SQUARE_SIZE*2));
	unit->realAirLosRadius=(int) (ud->airLosRadius/(SQUARE_SIZE*4));
	unit->upright=ud->upright;
	unit->xsize=ud->xsize;
	unit->ysize=ud->ysize;
	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->hasRadarCapacity=unit->radarRadius || unit->sonarRadius || unit->jammerRadius || unit->sonarJamRadius;
	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)));
	
	if(ud->highTrajectoryType==1)
		unit->useHighTrajectory=true;

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

	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) 
			(*info) << "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;
		unit->mass=ud->mass;
		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;

		//Unit parameters
		unit->mass = ud->mass;	//Should this not be done for all units?!  //buildings have mass 100000 to show they are immobile
//		unit->moveType = new CDummyMoveType(unit);	//Disable old movetype-system.

		//Uggly addition of UnitAI.
//		unit->ai = new CUnitAI();
//		unit->ai->moveAAI = new CSurfaceMoveAAI(unit);

	} 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;

		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;

			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.5+(gs->randFloat()-0.3)*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.5: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->Init();

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

END_TIME_PROFILE("Unit loader");
	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;
}