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