void CSceneManager::AddUnit(char* name, float x, float y, int camp) { CUnit* unit = NULL; unit = new CUnit(m_pRs, name, m_pMap); unit->Init((void*)&camp); unit->SetPoint(x, y); m_objs.push_back(unit); CCommander::m_units->push_back(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 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; }
/** ** Parse unit ** ** @param l Lua state. ** ** @todo Verify that vision table is always correct (transporter) ** @todo (PlaceUnit() and host-info). */ static int CclUnit(lua_State *l) { const int slot = LuaToNumber(l, 1); if (!lua_istable(l, 2)) { LuaError(l, "incorrect argument"); } CUnit *unit = NULL; CUnitType *type = NULL; CUnitType *seentype = NULL; CPlayer *player = NULL; // Parse the list: const int args = lua_rawlen(l, 2); for (int j = 0; j < args; ++j) { const char *value = LuaToString(l, 2, j + 1); ++j; if (!strcmp(value, "type")) { type = UnitTypeByIdent(LuaToString(l, 2, j + 1)); } else if (!strcmp(value, "seen-type")) { seentype = UnitTypeByIdent(LuaToString(l, 2, j + 1)); } else if (!strcmp(value, "player")) { player = &Players[LuaToNumber(l, 2, j + 1)]; // During a unit's death animation (when action is "die" but the // unit still has its original type, i.e. it's still not a corpse) // the unit is already removed from map and from player's // unit list (=the unit went through LetUnitDie() which // calls RemoveUnit() and UnitLost()). Such a unit should not // be put on player's unit list! However, this state is not // easily detected from this place. It seems that it is // characterized by // unit->CurrentAction()==UnitActionDie so we have to wait // until we parsed at least Unit::Orders[]. Assert(type); unit = &UnitManager.GetSlotUnit(slot); unit->Init(*type); unit->Seen.Type = seentype; unit->Active = 0; unit->Removed = 0; Assert(UnitNumber(*unit) == slot); } else if (!strcmp(value, "current-sight-range")) { unit->CurrentSightRange = LuaToNumber(l, 2, j + 1); } else if (!strcmp(value, "refs")) { unit->Refs = LuaToNumber(l, 2, j + 1); } else if (!strcmp(value, "host-info")) { lua_rawgeti(l, 2, j + 1); if (!lua_istable(l, -1) || lua_rawlen(l, -1) != 4) { LuaError(l, "incorrect argument"); } Vec2i pos; int w; int h; pos.x = LuaToNumber(l, -1, 1); pos.y = LuaToNumber(l, -1, 2); w = LuaToNumber(l, -1, 3); h = LuaToNumber(l, -1, 4); MapSight(*player, pos, w, h, unit->CurrentSightRange, MapMarkTileSight); // Detectcloak works in container if (unit->Type->DetectCloak) { MapSight(*player, pos, w, h, unit->CurrentSightRange, MapMarkTileDetectCloak); } // Radar(Jammer) not. lua_pop(l, 1); } else if (!strcmp(value, "tile")) { lua_rawgeti(l, 2, j + 1); CclGetPos(l, &unit->tilePos.x , &unit->tilePos.y, -1); lua_pop(l, 1); unit->Offset = Map.getIndex(unit->tilePos); } else if (!strcmp(value, "seen-tile")) { lua_rawgeti(l, 2, j + 1); CclGetPos(l, &unit->Seen.tilePos.x , &unit->Seen.tilePos.y, -1); lua_pop(l, 1); } else if (!strcmp(value, "stats")) { unit->Stats = &type->Stats[LuaToNumber(l, 2, j + 1)]; } else if (!strcmp(value, "pixel")) { lua_rawgeti(l, 2, j + 1); CclGetPos(l, &unit->IX , &unit->IY, -1); lua_pop(l, 1); } else if (!strcmp(value, "seen-pixel")) { lua_rawgeti(l, 2, j + 1); CclGetPos(l, &unit->Seen.IX , &unit->Seen.IY, -1); lua_pop(l, 1); } else if (!strcmp(value, "frame")) { unit->Frame = LuaToNumber(l, 2, j + 1); } else if (!strcmp(value, "seen")) { unit->Seen.Frame = LuaToNumber(l, 2, j + 1); } else if (!strcmp(value, "not-seen")) { unit->Seen.Frame = UnitNotSeen; --j; } else if (!strcmp(value, "direction")) { unit->Direction = LuaToNumber(l, 2, j + 1); } else if (!strcmp(value, "damage-type")) { unit->DamagedType = LuaToNumber(l, 2, j + 1); } else if (!strcmp(value, "attacked")) { // FIXME : unsigned long should be better handled unit->Attacked = LuaToNumber(l, 2, j + 1); } else if (!strcmp(value, "auto-repair")) { unit->AutoRepair = 1; --j; } else if (!strcmp(value, "burning")) { unit->Burning = 1; --j; } else if (!strcmp(value, "destroyed")) { unit->Destroyed = 1; --j; } else if (!strcmp(value, "removed")) { unit->Removed = 1; --j; } else if (!strcmp(value, "selected")) { unit->Selected = 1; --j; } else if (!strcmp(value, "summoned")) { unit->Summoned = 1; --j; } else if (!strcmp(value, "waiting")) { unit->Waiting = 1; --j; } else if (!strcmp(value, "mine-low")) { unit->MineLow = 1; --j; } else if (!strcmp(value, "rescued-from")) { unit->RescuedFrom = &Players[LuaToNumber(l, 2, j + 1)]; } else if (!strcmp(value, "seen-by-player")) { const char *s = LuaToString(l, 2, j + 1); unit->Seen.ByPlayer = 0; for (int i = 0; i < PlayerMax && *s; ++i, ++s) { if (*s == '-' || *s == '_' || *s == ' ') { unit->Seen.ByPlayer &= ~(1 << i); } else { unit->Seen.ByPlayer |= (1 << i); } } } else if (!strcmp(value, "seen-destroyed")) { const char *s = LuaToString(l, 2, j + 1); unit->Seen.Destroyed = 0; for (int i = 0; i < PlayerMax && *s; ++i, ++s) { if (*s == '-' || *s == '_' || *s == ' ') { unit->Seen.Destroyed &= ~(1 << i); } else { unit->Seen.Destroyed |= (1 << i); } } } else if (!strcmp(value, "constructed")) { unit->Constructed = 1; --j; } else if (!strcmp(value, "seen-constructed")) { unit->Seen.Constructed = 1; --j; } else if (!strcmp(value, "seen-state")) { unit->Seen.State = LuaToNumber(l, 2, j + 1); } else if (!strcmp(value, "active")) { unit->Active = 1; --j; } else if (!strcmp(value, "ttl")) { // FIXME : unsigned long should be better handled unit->TTL = LuaToNumber(l, 2, j + 1); } else if (!strcmp(value, "threshold")) { // FIXME : unsigned long should be better handled unit->Threshold = LuaToNumber(l, 2, j + 1); } else if (!strcmp(value, "group-id")) { unit->GroupId = LuaToNumber(l, 2, j + 1); } else if (!strcmp(value, "last-group")) { unit->LastGroup = LuaToNumber(l, 2, j + 1); } else if (!strcmp(value, "resources-held")) { unit->ResourcesHeld = LuaToNumber(l, 2, j + 1); } else if (!strcmp(value, "current-resource")) { lua_rawgeti(l, 2, j + 1); lua_pushvalue(l, -1); unit->CurrentResource = CclGetResourceByName(l); lua_pop(l, 1); } else if (!strcmp(value, "pathfinder-input")) { lua_rawgeti(l, 2, j + 1); lua_pushvalue(l, -1); unit->pathFinderData->input.Load(l); lua_pop(l, 1); } else if (!strcmp(value, "pathfinder-output")) { lua_rawgeti(l, 2, j + 1); lua_pushvalue(l, -1); unit->pathFinderData->output.Load(l); lua_pop(l, 1); } else if (!strcmp(value, "wait")) { unit->Wait = LuaToNumber(l, 2, j + 1); } else if (!strcmp(value, "anim-data")) { lua_rawgeti(l, 2, j + 1); CAnimations::LoadUnitAnim(l, *unit, -1); lua_pop(l, 1); } else if (!strcmp(value, "wait-anim-data")) { lua_rawgeti(l, 2, j + 1); CAnimations::LoadWaitUnitAnim(l, *unit, -1); lua_pop(l, 1); } else if (!strcmp(value, "blink")) { unit->Blink = LuaToNumber(l, 2, j + 1); } else if (!strcmp(value, "moving")) { unit->Moving = 1; --j; } else if (!strcmp(value, "re-cast")) { unit->ReCast = 1; --j; } else if (!strcmp(value, "boarded")) { unit->Boarded = 1; --j; } else if (!strcmp(value, "next-worker")) { lua_rawgeti(l, 2, j + 1); lua_pushvalue(l, -1); unit->NextWorker = CclGetUnitFromRef(l); lua_pop(l, 1); } else if (!strcmp(value, "resource-workers")) { lua_rawgeti(l, 2, j + 1); lua_pushvalue(l, -1); unit->Resource.Workers = CclGetUnitFromRef(l); lua_pop(l, 1); } else if (!strcmp(value, "resource-assigned")) { lua_rawgeti(l, 2, j + 1); lua_pushvalue(l, -1); unit->Resource.Assigned = LuaToNumber(l, -1); lua_pop(l, 1); } else if (!strcmp(value, "resource-active")) { lua_rawgeti(l, 2, j + 1); lua_pushvalue(l, -1); unit->Resource.Active = LuaToNumber(l, -1); lua_pop(l, 1); } else if (!strcmp(value, "units-boarded-count")) { unit->BoardCount = LuaToNumber(l, 2, j + 1); } else if (!strcmp(value, "units-contained")) { int subargs; int k; lua_rawgeti(l, 2, j + 1); if (!lua_istable(l, -1)) { LuaError(l, "incorrect argument"); } subargs = lua_rawlen(l, -1); for (k = 0; k < subargs; ++k) { lua_rawgeti(l, -1, k + 1); CUnit *u = CclGetUnitFromRef(l); lua_pop(l, 1); u->AddInContainer(*unit); } lua_pop(l, 1); } else if (!strcmp(value, "orders")) { lua_rawgeti(l, 2, j + 1); lua_pushvalue(l, -1); CclParseOrders(l, *unit); lua_pop(l, 1); // now we know unit's action so we can assign it to a player Assert(player != NULL); unit->AssignToPlayer(*player); if (unit->CurrentAction() == UnitActionBuilt) { DebugPrint("HACK: the building is not ready yet\n"); // HACK: the building is not ready yet unit->Player->UnitTypesCount[type->Slot]--; if (unit->Active) { unit->Player->UnitTypesAiActiveCount[type->Slot]--; } } } else if (!strcmp(value, "critical-order")) { lua_rawgeti(l, 2, j + 1); lua_pushvalue(l, -1); CclParseOrder(l, *unit , &unit->CriticalOrder); lua_pop(l, 1); } else if (!strcmp(value, "saved-order")) { lua_rawgeti(l, 2, j + 1); lua_pushvalue(l, -1); CclParseOrder(l, *unit, &unit->SavedOrder); lua_pop(l, 1); } else if (!strcmp(value, "new-order")) { lua_rawgeti(l, 2, j + 1); lua_pushvalue(l, -1); CclParseOrder(l, *unit, &unit->NewOrder); lua_pop(l, 1); } else if (!strcmp(value, "goal")) { unit->Goal = &UnitManager.GetSlotUnit(LuaToNumber(l, 2, j + 1)); } else if (!strcmp(value, "auto-cast")) { const char *s = LuaToString(l, 2, j + 1); Assert(SpellTypeByIdent(s)); if (!unit->AutoCastSpell) { unit->AutoCastSpell = new char[SpellTypeTable.size()]; memset(unit->AutoCastSpell, 0, SpellTypeTable.size()); } unit->AutoCastSpell[SpellTypeByIdent(s)->Slot] = 1; } else if (!strcmp(value, "spell-cooldown")) { lua_rawgeti(l, 2, j + 1); if (!lua_istable(l, -1) || lua_rawlen(l, -1) != SpellTypeTable.size()) { LuaError(l, "incorrect argument"); } if (!unit->SpellCoolDownTimers) { unit->SpellCoolDownTimers = new int[SpellTypeTable.size()]; memset(unit->SpellCoolDownTimers, 0, SpellTypeTable.size() * sizeof(int)); } for (size_t k = 0; k < SpellTypeTable.size(); ++k) { unit->SpellCoolDownTimers[k] = LuaToNumber(l, -1, k + 1); } lua_pop(l, 1); } else { const int index = UnitTypeVar.VariableNameLookup[value];// User variables if (index != -1) { // Valid index lua_rawgeti(l, 2, j + 1); DefineVariableField(l, unit->Variable + index, -1); lua_pop(l, 1); continue; } LuaError(l, "Unit: Unsupported tag: %s" _C_ value); } } // Unit may not have been assigned to a player before now. If not, // do so now. It is only assigned earlier if we have orders. // for loading of units from a MAP, and not a savegame, we won't // have orders for those units. They should appear here as if // they were just created. if (!unit->Player) { Assert(player); unit->AssignToPlayer(*player); UpdateForNewUnit(*unit, 0); } // Revealers are units that can see while removed if (unit->Removed && unit->Type->Revealer) { MapMarkUnitSight(*unit); } // Fix Colors for rescued units. if (unit->RescuedFrom) { unit->Colors = &unit->RescuedFrom->UnitColors; } return 0; }