CObject_pointer<CFeature>* FeatureLoaderLoadFeature( string name, float3 pos, int team ) { FeatureDef *def = featureHandler->GetFeatureDef(name); CFeature* feature = new CFeature(); feature->Initialize( pos,def,0, 0, team,"" ); return new CObject_pointer<CFeature>(feature); }
CFeature* CFeatureHandler::CreateWreckage(const float3& pos, const std::string& name, float rot, int facing, int iter, int team, int allyteam, bool emitSmoke, std::string fromUnit, const float3& speed) { const FeatureDef* fd; const std::string* defname = &name; int i = iter; do { if (defname->empty()) return NULL; fd = GetFeatureDef(*defname); if (!fd) return NULL; defname = &(fd->deathFeature); }while (--i > 0); if (luaRules && !luaRules->AllowFeatureCreation(fd, team, pos)) return NULL; if (!fd->modelname.empty()) { if (fd->resurrectable==0 || (iter>1 && fd->resurrectable<0)) fromUnit = ""; CFeature* f = new CFeature; f->Initialize(pos, fd, (short int) rot, facing, team, allyteam, fromUnit, speed, fd->smokeTime); return f; } return NULL; }
void CFeatureHandler::TerrainChanged(int x1, int y1, int x2, int y2) { ASSERT_SYNCED_MODE; vector<int> quads=qf->GetQuadsRectangle(float3(x1*SQUARE_SIZE,0,y1*SQUARE_SIZE), float3(x2*SQUARE_SIZE,0,y2*SQUARE_SIZE)); // logOutput.Print("Checking feature pos %i",quads.size()); for(vector<int>::iterator qi=quads.begin();qi!=quads.end();++qi){ list<CFeature*>::iterator fi; list<CFeature*>& features = qf->baseQuads[*qi].features; for(fi = features.begin(); fi != features.end(); ++fi) { CFeature* feature = *fi; float3& fpos = feature->pos; if (fpos.y > ground->GetHeight(fpos.x, fpos.z)) { SetFeatureUpdateable(feature); if (feature->def->floating){ feature->finalHeight = ground->GetHeight(fpos.x, fpos.z); } else { feature->finalHeight = ground->GetHeight2(fpos.x, fpos.z); } feature->CalculateTransform (); } } } }
void CFeatureHandler::TerrainChanged(int x1, int y1, int x2, int y2) { std::vector<int> quads = qf->GetQuadsRectangle(float3(x1 * SQUARE_SIZE, 0, y1 * SQUARE_SIZE), float3(x2 * SQUARE_SIZE, 0, y2 * SQUARE_SIZE)); for (std::vector<int>::iterator qi = quads.begin(); qi != quads.end(); ++qi) { std::list<CFeature*>::const_iterator fi; const list<CFeature*>& features = qf->GetQuad(*qi).features; for (fi = features.begin(); fi != features.end(); ++fi) { CFeature* feature = *fi; float3& fpos = feature->pos; float gh = ground->GetHeight2(fpos.x, fpos.z); float wh = gh; if(feature->def->floating) wh = ground->GetHeight(fpos.x, fpos.z); if (fpos.y > wh || fpos.y < gh) { SetFeatureUpdateable(feature); feature->finalHeight = wh; feature->CalculateTransform (); } } } }
CFeature* CFeatureHandler::CreateWreckage(const float3& pos, const std::string& name, float rot, int facing, int iter, int team, int allyteam, bool emitSmoke, std::string fromUnit, const float3& speed) { ASSERT_SYNCED_MODE; if (name.empty()) { return NULL; } const FeatureDef* fd = GetFeatureDef(name); if (!fd) { return NULL; } if (iter > 1) { return CreateWreckage(pos, fd->deathFeature, rot, facing, iter - 1, team, allyteam, emitSmoke, "", speed); } else { if (luaRules && !luaRules->AllowFeatureCreation(fd, team, pos)) { return NULL; } if (!fd->modelname.empty()) { CFeature* f = SAFE_NEW CFeature; f->Initialize(pos, fd, (short int) rot, facing, team, fromUnit, speed); // allow area-reclaiming wrecks of all units, including your own (they set allyteam = -1) f->allyteam = allyteam; if (emitSmoke && f->blocking) f->emitSmokeTime = 300; return f; } } return NULL; }
void CFeatureHandler::Update() { SCOPED_TIMER("Feature::Update"); if ((gs->frameNum & 31) == 0) { // let all areareclaimers choose a target with a different id bool dontClear = false; for (std::list<int>::iterator it = toBeFreedIDs.begin(); it != toBeFreedIDs.end(); ++it) { if (CBuilderCAI::IsFeatureBeingReclaimed(*it)) { // postpone recycling dontClear = true; break; } } if (!dontClear) freeIDs.splice(freeIDs.end(), toBeFreedIDs, toBeFreedIDs.begin(), toBeFreedIDs.end()); } if(!toBeRemoved.empty()) { GML_RECMUTEX_LOCK(feat); // Update GML_RECMUTEX_LOCK(quad); // Update while (!toBeRemoved.empty()) { CFeatureSet::iterator it = activeFeatures.find(toBeRemoved.back()); toBeRemoved.pop_back(); if (it != activeFeatures.end()) { CFeature* feature = *it; toBeFreedIDs.push_back(feature->id); activeFeatures.erase(feature); if (feature->drawQuad >= 0) { DrawQuad* dq = &drawQuads[feature->drawQuad]; dq->features.erase(feature); } if (feature->inUpdateQue) { updateFeatures.erase(feature); } fadeFeatures.erase(feature); fadeFeaturesS3O.erase(feature); delete feature; } } } CFeatureSet::iterator fi = updateFeatures.begin(); while (fi != updateFeatures.end()) { CFeature* feature = *fi; ++fi; if (!feature->Update()) { // remove it feature->inUpdateQue = false; updateFeatures.erase(feature); } } }
int CUnitHandler::TestBuildSquare(const float3& pos, const UnitDef* unitdef, CFeature*& feature, int allyteam) { if (pos.x < 0 || pos.x >= gs->mapx * SQUARE_SIZE || pos.z < 0 || pos.z >= gs->mapy * SQUARE_SIZE) { return 0; } int ret = 2; int yardxpos = int(pos.x + 4) / SQUARE_SIZE; int yardypos = int(pos.z + 4) / SQUARE_SIZE; CSolidObject* s; if ((s = groundBlockingObjectMap->GroundBlocked(yardypos * gs->mapx + yardxpos))) { CFeature* f; if ((f = dynamic_cast<CFeature*>(s))) { if ((allyteam < 0) || f->IsInLosForAllyTeam(allyteam)) { if (!f->def->reclaimable) { return 0; } feature = f; } } else if (!dynamic_cast<CUnit*>(s) || (allyteam < 0) || (((CUnit*) s)->losStatus[allyteam] & LOS_INLOS)) { if (s->immobile) { return 0; } else { ret = 1; } } } const float groundheight = ground->GetHeight2(pos.x, pos.z); if (!unitdef->floater || groundheight > 0.0f) { // if we are capable of floating, only test local // height difference if terrain is above sea-level const float* heightmap = readmap->GetHeightmap(); int x = (int) (pos.x / SQUARE_SIZE); int z = (int) (pos.z / SQUARE_SIZE); float orgh = readmap->orgheightmap[z * (gs->mapx + 1) + x]; float h = heightmap[z * (gs->mapx + 1) + x]; float hdif = unitdef->maxHeightDif; if (pos.y > orgh + hdif && pos.y > h + hdif) { return 0; } if (pos.y < orgh - hdif && pos.y < h - hdif) { return 0; } } if (!unitdef->floater && groundheight < -unitdef->maxWaterDepth) { // ground is deeper than our maxWaterDepth, cannot build here return 0; } if (groundheight > -unitdef->minWaterDepth) { // ground is shallower than our minWaterDepth, cannot build here return 0; } return ret; }
void CFeatureHandler::LoadFeaturesFromMap(bool onlyCreateDefs) { // add default tree and geo FeatureDefs defined by the map const int numFeatureTypes = readmap->GetNumFeatureTypes(); for (int a = 0; a < numFeatureTypes; ++a) { const string& name = StringToLower(readmap->GetFeatureTypeName(a)); if (GetFeatureDef(name, false) == NULL) { if (name.find("treetype") != string::npos) { AddFeatureDef(name, CreateDefaultTreeFeatureDef(name)); } else if (name.find("geovent") != string::npos) { AddFeatureDef(name, CreateDefaultGeoFeatureDef(name)); } else { LOG_L(L_ERROR, "[%s] unknown map feature type \"%s\"", __FUNCTION__, name.c_str()); } } } // add a default geovent FeatureDef if the map did not if (GetFeatureDef("geovent", false) == NULL) { AddFeatureDef("geovent", CreateDefaultGeoFeatureDef("geovent")); } if (!onlyCreateDefs) { // create map-specified feature instances const int numFeatures = readmap->GetNumFeatures(); MapFeatureInfo* mfi = new MapFeatureInfo[numFeatures]; readmap->GetFeatureInfo(mfi); for (int a = 0; a < numFeatures; ++a) { const string& name = StringToLower(readmap->GetFeatureTypeName(mfi[a].featureType)); map<string, const FeatureDef*>::iterator def = featureDefs.find(name); if (def == featureDefs.end()) { LOG_L(L_ERROR, "Unknown feature named '%s'", name.c_str()); continue; } const float ypos = ground->GetHeightReal(mfi[a].pos.x, mfi[a].pos.z); const float3 fpos = float3(mfi[a].pos.x, ypos, mfi[a].pos.z); const FeatureDef* fdef = def->second; CFeature* f = new CFeature(); f->Initialize(fpos, fdef, (short int) mfi[a].rotation, 0, -1, -1, NULL); } delete[] mfi; } }
std::vector<CSolidObject*> CQuadField::GetSolidsExact( const float3& pos, const float radius, const unsigned int physicalStateBits, const unsigned int collisionStateBits ) { GML_RECMUTEX_LOCK(qnum); // GetSolidsExact const std::vector<int>& quads = GetQuads(pos, radius); const int tempNum = gs->tempNum++; std::vector<CSolidObject*> solids; std::vector<int>::const_iterator qi; std::list<CUnit*>::iterator ui; std::list<CFeature*>::iterator fi; for (qi = quads.begin(); qi != quads.end(); ++qi) { for (ui = baseQuads[*qi].units.begin(); ui != baseQuads[*qi].units.end(); ++ui) { CUnit* u = *ui; if (u->tempNum == tempNum) continue; if (!u->HasPhysicalStateBit(physicalStateBits)) continue; if (!u->HasCollidableStateBit(collisionStateBits)) continue; if ((pos - u->midPos).SqLength() >= Square(radius + u->radius)) continue; u->tempNum = tempNum; solids.push_back(u); } for (fi = baseQuads[*qi].features.begin(); fi != baseQuads[*qi].features.end(); ++fi) { CFeature* f = *fi; if (f->tempNum == tempNum) continue; if (!f->HasPhysicalStateBit(physicalStateBits)) continue; if (!f->HasCollidableStateBit(collisionStateBits)) continue; if ((pos - f->midPos).SqLength() >= Square(radius + f->radius)) continue; f->tempNum = tempNum; solids.push_back(f); } } return solids; }
float CGameHelper::GuiTraceRayFeature(const float3& start, const float3& dir, float length, CFeature*& feature) { float nearHit = length; GML_RECMUTEX_LOCK(quad); // GuiTraceRayFeature std::vector<int> quads = qf->GetQuadsOnRay(start, dir, length); std::vector<int>::iterator qi; for (qi = quads.begin(); qi != quads.end(); ++qi) { const CQuadField::Quad& quad = qf->GetQuad(*qi); std::list<CFeature*>::const_iterator ui; // NOTE: switch this to custom volumes fully? // (not used for any LOF checks, maybe wasteful) for (ui = quad.features.begin(); ui != quad.features.end(); ++ui) { CFeature* f = *ui; if (!gu->spectatingFullView && !f->IsInLosForAllyTeam(gu->myAllyTeam)) { continue; } if (f->noSelect) { continue; } CollisionVolume* cv = f->collisionVolume; const float3& midPosOffset = cv? cv->GetOffsets(): ZeroVector; const float3 dif = (f->midPos + midPosOffset) - start; float closeLength = dif.dot(dir); if (closeLength < 0) continue; if (closeLength > nearHit) continue; float3 closeVect = dif - dir * closeLength; if (closeVect.SqLength() < f->sqRadius) { nearHit = closeLength; feature = f; } } } return nearHit; }
void CFeatureHandler::LoadSaveFeatures(CLoadSaveInterface* file, bool loading) { if(loading) freeIDs.clear(); for(int a=0;a<MAX_FEATURES;++a){ bool exists=!!features[a]; file->lsBool(exists); if(exists){ if(loading){ overrideId=a; float3 pos; file->lsFloat3(pos); string def; file->lsString(def); if(featureDefs.find(def)==featureDefs.end()) GetFeatureDef(def); short rotation; file->lsShort(rotation); string fromUnit; file->lsString(fromUnit); CFeature* f = SAFE_NEW CFeature; f->Initialize (pos,featureDefs[def],rotation,0,-1,fromUnit); } else { file->lsFloat3(features[a]->pos); file->lsString(features[a]->def->myName); file->lsShort(features[a]->heading); file->lsString(features[a]->createdFromUnit); } CFeature* f=features[a]; file->lsFloat(f->health); file->lsFloat(f->reclaimLeft); file->lsInt(f->allyteam); } else { if(loading) freeIDs.push_back(a); } } overrideId=-1; }
void CFeatureHandler::Update() { ASSERT_SYNCED_MODE; START_TIME_PROFILE while (!toBeRemoved.empty()) { CFeature* feature = features[toBeRemoved.back()]; toBeRemoved.pop_back(); if (feature) { freeIDs.push_back(feature->id); features[feature->id] = 0; if (feature->drawQuad >= 0) { DrawQuad* dq = &drawQuads[feature->drawQuad]; dq->features.erase(feature); } if (feature->inUpdateQue) { updateFeatures.erase(feature->id); } delete feature; } } SPRING_HASH_SET<int>::iterator fi=updateFeatures.begin(); while(fi!= updateFeatures.end()){ CFeature* feature = features[*fi]; const bool remove = !feature->Update(); if (remove) { feature->inUpdateQue = false; updateFeatures.erase(fi++); } else { ++fi; } } END_TIME_PROFILE("Feature::Update"); }
// called by {CRifle, CBeamLaser, CLightningCannon}::Fire(), CWeapon::HaveFreeLineOfFire(), and Skirmish AIs float TraceRay( const float3& start, const float3& dir, float length, int avoidFlags, const CUnit* owner, CUnit*& hitUnit, CFeature*& hitFeature, CollisionQuery* hitColQuery ) { const bool ignoreEnemies = ((avoidFlags & Collision::NOENEMIES ) != 0); const bool ignoreAllies = ((avoidFlags & Collision::NOFRIENDLIES) != 0); const bool ignoreFeatures = ((avoidFlags & Collision::NOFEATURES ) != 0); const bool ignoreNeutrals = ((avoidFlags & Collision::NONEUTRALS ) != 0); const bool ignoreGround = ((avoidFlags & Collision::NOGROUND ) != 0); const bool ignoreUnits = ignoreEnemies && ignoreAllies && ignoreNeutrals; hitFeature = NULL; hitUnit = NULL; if (dir == ZeroVector) return -1.0f; if (!ignoreFeatures || !ignoreUnits) { GML_RECMUTEX_LOCK(quad); // TraceRay CollisionQuery cq; int* begQuad = NULL; int* endQuad = NULL; quadField->GetQuadsOnRay(start, dir, length, begQuad, endQuad); // locally point somewhere non-NULL; we cannot pass hitColQuery // to DetectHit directly because each call resets it internally if (hitColQuery == NULL) hitColQuery = &cq; // feature intersection if (!ignoreFeatures) { for (int* quadPtr = begQuad; quadPtr != endQuad; ++quadPtr) { const CQuadField::Quad& quad = quadField->GetQuad(*quadPtr); for (std::list<CFeature*>::const_iterator ui = quad.features.begin(); ui != quad.features.end(); ++ui) { CFeature* f = *ui; // NOTE: // if f is non-blocking, ProjectileHandler will not test // for collisions with projectiles so we can skip it here if (!f->HasCollidableStateBit(CSolidObject::CSTATE_BIT_QUADMAPRAYS)) continue; if (CCollisionHandler::DetectHit(f, start, start + dir * length, &cq, true)) { const float len = cq.GetHitPosDist(start, dir); // we want the closest feature (intersection point) on the ray if (len < length) { length = len; hitFeature = f; *hitColQuery = cq; } } } } } // unit intersection if (!ignoreUnits) { for (int* quadPtr = begQuad; quadPtr != endQuad; ++quadPtr) { const CQuadField::Quad& quad = quadField->GetQuad(*quadPtr); for (std::list<CUnit*>::const_iterator ui = quad.units.begin(); ui != quad.units.end(); ++ui) { CUnit* u = *ui; if (u == owner) continue; if (!u->HasCollidableStateBit(CSolidObject::CSTATE_BIT_QUADMAPRAYS)) continue; if (ignoreAllies && u->allyteam == owner->allyteam) continue; if (ignoreNeutrals && u->IsNeutral()) continue; if (ignoreEnemies && u->allyteam != owner->allyteam) continue; if (CCollisionHandler::DetectHit(u, start, start + dir * length, &cq, true)) { const float len = cq.GetHitPosDist(start, dir); // we want the closest unit (intersection point) on the ray if (len < length) { length = len; hitUnit = u; *hitColQuery = cq; } } } } if (hitUnit) hitFeature = NULL; } } if (!ignoreGround) { // ground intersection const float groundLength = ground->LineGroundCol(start, start + dir * length); if (length > groundLength && groundLength > 0.0f) { length = groundLength; hitUnit = NULL; hitFeature = NULL; } } return length; }
int CAICallback::HandleCommand(int commandId, void* data) { switch (commandId) { case AIHCQuerySubVersionId: { return 1; // current version of Handle Command interface } break; case AIHCAddMapPointId: { const AIHCAddMapPoint* cmdData = static_cast<AIHCAddMapPoint*>(data); /* TODO: gu->myPlayerNum makes the command to look like as it comes from the local player, "team" should be used (but needs some major changes in other engine parts) */ clientNet->Send(CBaseNetProtocol::Get().SendMapDrawPoint(gu->myPlayerNum, (short)cmdData->pos.x, (short)cmdData->pos.z, std::string(cmdData->label), false)); return 1; } break; case AIHCAddMapLineId: { const AIHCAddMapLine* cmdData = static_cast<AIHCAddMapLine*>(data); // see TODO above clientNet->Send(CBaseNetProtocol::Get().SendMapDrawLine(gu->myPlayerNum, (short)cmdData->posfrom.x, (short)cmdData->posfrom.z, (short)cmdData->posto.x, (short)cmdData->posto.z, false)); return 1; } break; case AIHCRemoveMapPointId: { const AIHCRemoveMapPoint* cmdData = static_cast<AIHCRemoveMapPoint*>(data); // see TODO above clientNet->Send(CBaseNetProtocol::Get().SendMapErase(gu->myPlayerNum, (short)cmdData->pos.x, (short)cmdData->pos.z)); return 1; } break; case AIHCSendStartPosId: case AIHCGetUnitDefByIdId: case AIHCGetWeaponDefByIdId: case AIHCGetFeatureDefByIdId: case AIHCGetDataDirId: { // NOTE: these commands should never arrive, handled in SSkirmishAICallbackImpl assert(false); return 0; } break; case AIHCTraceRayId: { AIHCTraceRay* cmdData = static_cast<AIHCTraceRay*>(data); if (CHECK_UNITID(cmdData->srcUID)) { const CUnit* srcUnit = unitHandler->GetUnit(cmdData->srcUID); if (srcUnit != nullptr) { CUnit* hitUnit = nullptr; CFeature* hitFeature = nullptr; //FIXME add COLLISION_NOFEATURE? const float realLen = TraceRay::TraceRay(cmdData->rayPos, cmdData->rayDir, cmdData->rayLen, cmdData->flags, srcUnit, hitUnit, hitFeature); if (hitUnit != nullptr) { myAllyTeamId = teamHandler->AllyTeam(team); if (unit_IsInLos(hitUnit)) { cmdData->rayLen = realLen; cmdData->hitUID = hitUnit->id; } } } } return 1; } break; case AIHCFeatureTraceRayId: { AIHCFeatureTraceRay* cmdData = static_cast<AIHCFeatureTraceRay*>(data); if (CHECK_UNITID(cmdData->srcUID)) { const CUnit* srcUnit = unitHandler->GetUnit(cmdData->srcUID); if (srcUnit != nullptr) { CUnit* hitUnit = nullptr; CFeature* hitFeature = nullptr; //FIXME add COLLISION_NOENEMIES || COLLISION_NOFRIENDLIES || COLLISION_NONEUTRALS? const float realLen = TraceRay::TraceRay(cmdData->rayPos, cmdData->rayDir, cmdData->rayLen, cmdData->flags, srcUnit, hitUnit, hitFeature); if (hitFeature != nullptr) { if (hitFeature->IsInLosForAllyTeam(teamHandler->AllyTeam(team))) { cmdData->rayLen = realLen; cmdData->hitFID = hitFeature->id; } } } } return 1; } break; case AIHCPauseId: { AIHCPause* cmdData = static_cast<AIHCPause*>(data); clientNet->Send(CBaseNetProtocol::Get().SendPause(gu->myPlayerNum, cmdData->enable)); LOG("Skirmish AI controlling team %i paused the game, reason: %s", team, cmdData->reason != NULL ? cmdData->reason : "UNSPECIFIED"); return 1; } break; case AIHCDebugDrawId: { AIHCDebugDraw* cmdData = static_cast<AIHCDebugDraw*>(data); switch (cmdData->cmdMode) { case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_ADD_GRAPH_POINT: { debugDrawerAI->AddGraphPoint(this->team, cmdData->lineId, cmdData->x, cmdData->y); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_DEL_GRAPH_POINTS: { debugDrawerAI->DelGraphPoints(this->team, cmdData->lineId, cmdData->numPoints); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_SET_GRAPH_POS: { debugDrawerAI->SetGraphPos(this->team, cmdData->x, cmdData->y); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_SET_GRAPH_SIZE: { debugDrawerAI->SetGraphSize(this->team, cmdData->w, cmdData->h); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_SET_GRAPH_LINE_COLOR: { debugDrawerAI->SetGraphLineColor(this->team, cmdData->lineId, cmdData->color); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_SET_GRAPH_LINE_LABEL: { debugDrawerAI->SetGraphLineLabel(this->team, cmdData->lineId, cmdData->label); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_ADD_OVERLAY_TEXTURE: { cmdData->texHandle = debugDrawerAI->AddOverlayTexture( this->team, cmdData->texData, int(cmdData->w), // interpret as absolute width int(cmdData->h) // interpret as absolute height ); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_UPDATE_OVERLAY_TEXTURE: { debugDrawerAI->UpdateOverlayTexture( this->team, cmdData->texHandle, cmdData->texData, int(cmdData->x), // interpret as absolute pixel col int(cmdData->y), // interpret as absolute pixel row int(cmdData->w), // interpret as absolute width int(cmdData->h) // interpret as absolute height ); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_DEL_OVERLAY_TEXTURE: { debugDrawerAI->DelOverlayTexture(this->team, cmdData->texHandle); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_SET_OVERLAY_TEXTURE_POS: { debugDrawerAI->SetOverlayTexturePos(this->team, cmdData->texHandle, cmdData->x, cmdData->y); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_SET_OVERLAY_TEXTURE_SIZE: { debugDrawerAI->SetOverlayTextureSize(this->team, cmdData->texHandle, cmdData->w, cmdData->h); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_SET_OVERLAY_TEXTURE_LABEL: { debugDrawerAI->SetOverlayTextureLabel(this->team, cmdData->texHandle, cmdData->label); } break; default: { } break; } return 1; } break; default: { return 0; } } }
void CFeatureHandler::Update() { SCOPED_TIMER("FeatureHandler::Update"); if ((gs->frameNum & 31) == 0) { // let all areareclaimers choose a target with a different id bool dontClear = false; for (list<int>::iterator it = toBeFreedIDs.begin(); it != toBeFreedIDs.end(); ++it) { if (CBuilderCAI::IsFeatureBeingReclaimed(*it)) { // postpone recycling dontClear = true; break; } } if (!dontClear) freeIDs.splice(freeIDs.end(), toBeFreedIDs, toBeFreedIDs.begin(), toBeFreedIDs.end()); } { GML_STDMUTEX_LOCK(rfeat); // Update if(!toBeRemoved.empty()) { GML_RECMUTEX_LOCK(obj); // Update eventHandler.DeleteSyncedObjects(); GML_RECMUTEX_LOCK(feat); // Update eventHandler.DeleteSyncedFeatures(); GML_RECMUTEX_LOCK(quad); // Update while (!toBeRemoved.empty()) { CFeature* feature = GetFeature(toBeRemoved.back()); toBeRemoved.pop_back(); if (feature) { int delID = feature->id; toBeFreedIDs.push_back(delID); activeFeatures.erase(feature); features[delID] = 0; if (feature->inUpdateQue) { updateFeatures.erase(feature); } CSolidObject::SetDeletingRefID(delID + uh->MaxUnits()); delete feature; CSolidObject::SetDeletingRefID(-1); } } } eventHandler.UpdateFeatures(); } CFeatureSet::iterator fi = updateFeatures.begin(); while (fi != updateFeatures.end()) { CFeature* feature = *fi; ++fi; if (!feature->Update()) { // remove it feature->inUpdateQue = false; updateFeatures.erase(feature); } } }
void CFeatureQuadDrawer::DrawQuad(int x, int y) { CFeatureDrawer::DrawQuad* dq = &(*drawQuads)[y * drawQuadsX + x]; for (set<CFeature*>::iterator fi = dq->features.begin(); fi != dq->features.end(); ++fi) { CFeature* f = (*fi); const FeatureDef* def = f->def; if (def->drawType == DRAWTYPE_MODEL && (gu->spectatingFullView || f->IsInLosForAllyTeam(gu->myAllyTeam))) { if (drawReflection) { float3 zeroPos; if (f->midPos.y < 0) { zeroPos = f->midPos; } else { float dif = f->midPos.y - camera->pos.y; zeroPos = camera->pos * (f->midPos.y / dif) + f->midPos * (-camera->pos.y / dif); } if (ground->GetApproximateHeight(zeroPos.x, zeroPos.z) > f->radius) { continue; } } if (drawRefraction) { if (f->pos.y > 0) continue; } float sqDist = (f->pos - camera->pos).SqLength2D(); float farLength = f->sqRadius * unitDrawDist * unitDrawDist; if(statFeatures && (f->reclaimLeft < 1.0f || f->resurrectProgress > 0.0f)) statFeatures->push_back(f); if (sqDist < farLength) { float sqFadeDistE; float sqFadeDistB; if(farLength < sqFadeDistEnd) { sqFadeDistE = farLength; sqFadeDistB = farLength * 0.75f * 0.75f; } else { sqFadeDistE = sqFadeDistEnd; sqFadeDistB = sqFadeDistBegin; } if(sqDist < sqFadeDistB) { f->tempalpha = 0.99f; if (f->model->type == MODELTYPE_3DO) { unitDrawer->DrawFeatureStatic(f); } else { unitDrawer->QueS3ODraw(f, f->model->textureType); } } else if(sqDist < sqFadeDistE) { f->tempalpha = 1.0f - (sqDist - sqFadeDistB) / (sqFadeDistE - sqFadeDistB); if (f->model->type == MODELTYPE_3DO) { featureDrawer->fadeFeatures.insert(f); } else { featureDrawer->fadeFeaturesS3O.insert(f); } } } else { if (farFeatures) farFeatures->push_back(f); } } } }
CGameHelper::BuildSquareStatus CGameHelper::TestBuildSquare(const float3& pos, const float buildHeight, const UnitDef* unitdef, const MoveDef* moveDef, CFeature*& feature, int allyteam, bool synced) { if (!pos.IsInMap()) { return BUILDSQUARE_BLOCKED; } BuildSquareStatus ret = BUILDSQUARE_OPEN; const int yardxpos = int(pos.x + 4) / SQUARE_SIZE; const int yardypos = int(pos.z + 4) / SQUARE_SIZE; CSolidObject* s = groundBlockingObjectMap->GroundBlocked(yardxpos, yardypos); if (s != NULL) { CFeature* f = dynamic_cast<CFeature*>(s); if (f != NULL) { if ((allyteam < 0) || f->IsInLosForAllyTeam(allyteam)) { if (!f->def->reclaimable) { ret = BUILDSQUARE_BLOCKED; } else { ret = BUILDSQUARE_RECLAIMABLE; feature = f; } } } else if (!dynamic_cast<CUnit*>(s) || (allyteam < 0) || (static_cast<CUnit*>(s)->losStatus[allyteam] & LOS_INLOS)) { if (s->immobile) { ret = BUILDSQUARE_BLOCKED; } else { ret = BUILDSQUARE_OCCUPIED; } } if ((ret == BUILDSQUARE_BLOCKED) || (ret == BUILDSQUARE_OCCUPIED)) { if (CMoveMath::IsNonBlocking(s, moveDef, pos, buildHeight)) { ret = BUILDSQUARE_OPEN; } } if (ret == BUILDSQUARE_BLOCKED) { return ret; } } const float groundHeight = ground->GetHeightReal(pos.x, pos.z, synced); if (!unitdef->floatOnWater || groundHeight > 0.0f) { // if we are capable of floating, only test local // height difference IF terrain is above sea-level const float* orgHeightMap = readmap->GetOriginalHeightMapSynced(); const float* curHeightMap = readmap->GetCornerHeightMapSynced(); #ifdef USE_UNSYNCED_HEIGHTMAP if (!synced) { orgHeightMap = readmap->GetCornerHeightMapUnsynced(); curHeightMap = readmap->GetCornerHeightMapUnsynced(); } #endif const int sqx = pos.x / SQUARE_SIZE; const int sqz = pos.z / SQUARE_SIZE; const float orgHgt = orgHeightMap[sqz * gs->mapxp1 + sqx]; const float curHgt = curHeightMap[sqz * gs->mapxp1 + sqx]; const float difHgt = unitdef->maxHeightDif; if (pos.y > std::max(orgHgt + difHgt, curHgt + difHgt)) { return BUILDSQUARE_BLOCKED; } if (pos.y < std::min(orgHgt - difHgt, curHgt - difHgt)) { return BUILDSQUARE_BLOCKED; } } if (!unitdef->IsAllowedTerrainHeight(moveDef, groundHeight)) ret = BUILDSQUARE_BLOCKED; return ret; }
float GuiTraceRay( const float3& start, const float3& dir, float length, bool useRadar, const CUnit* exclude, CUnit*& hitUnit, CFeature*& hitFeature, bool groundOnly ) { hitUnit = NULL; hitFeature = NULL; if (dir == ZeroVector) return -1.0f; // ground intersection const float origlength = length; const float groundLength = ground->LineGroundCol(start, start + dir * origlength, false); float length2 = length; if (groundOnly) return groundLength; GML_RECMUTEX_LOCK(quad); // GuiTraceRay int* begQuad = NULL; int* endQuad = NULL; bool hitFactory = false; CollisionQuery cq; qf->GetQuadsOnRay(start, dir, length, begQuad, endQuad); std::list<CUnit*>::const_iterator ui; std::list<CFeature*>::const_iterator fi; for (int* quadPtr = begQuad; quadPtr != endQuad; ++quadPtr) { const CQuadField::Quad& quad = qf->GetQuad(*quadPtr); // Unit Intersection for (ui = quad.units.begin(); ui != quad.units.end(); ++ui) { CUnit* unit = *ui; if (unit == exclude) continue; if ((unit->allyteam == gu->myAllyTeam) || gu->spectatingFullView || (unit->losStatus[gu->myAllyTeam] & (LOS_INLOS | LOS_CONTRADAR)) || (useRadar && radarhandler->InRadar(unit, gu->myAllyTeam))) { CollisionVolume cv(unit->collisionVolume); if (unit->isIcon) { // for iconified units, just pretend the collision // volume is a sphere of radius <unit->IconRadius> // randomize it (by scaling up to a factor of 4) so // unit size cannot be determined by hovering mouse // over radar blips cv.Init(unit->iconRadius * (1.0f + (gu->usRandFloat() * 3.0f))); } if (CCollisionHandler::MouseHit(unit, start, start + dir * origlength, &cv, &cq)) { // get the distance to the ray-volume ingress point const float3& ingressPos = (cq.b0)? cq.p0 : cq.p1; const float3& egressPos = (cq.b1)? cq.p1 : cq.p0; const float ingressDist = (ingressPos - start).dot(dir); // same as (intPos - start).Length() const float egressDist = ( egressPos - start).dot(dir); // same as (intPos2 - start).Length() const bool isFactory = unit->unitDef->IsFactoryUnit(); // give units in a factory higher priority than the factory itself if (!hitUnit || (isFactory && ((hitFactory && ingressDist < length) || (!hitFactory && egressDist < length))) || (!isFactory && ((hitFactory && ingressDist < length2) || (!hitFactory && ingressDist < length)))) { hitFactory = isFactory; length = ingressDist; length2 = egressDist; hitUnit = unit; hitFeature = NULL; } } } } // Feature Intersection // NOTE: switch this to custom volumes fully? // (not used for any LOF checks, maybe wasteful) for (fi = quad.features.begin(); fi != quad.features.end(); ++fi) { CFeature* f = *fi; // FIXME add useradar? if (!gu->spectatingFullView && !f->IsInLosForAllyTeam(gu->myAllyTeam)) continue; if (f->noSelect) continue; if (CCollisionHandler::DetectHit(f, start, start + dir * origlength, &cq, true)) { const float3& ingressPos = (cq.b0)? cq.p0 : cq.p1; const float ingressDist = (ingressPos - start).dot(dir); // same as (intPos - start).Length() // we want the closest feature (intersection point) on the ray // give features in a factory (?) higher priority than the factory itself if (!hitUnit || ((hitFactory && ingressDist < length2) || (!hitFactory && ingressDist < length))) { hitFactory = false; length = ingressDist; hitFeature = f; hitUnit = NULL; } } } } if ((groundLength > 0.0f) && ((groundLength + 200.0f) < length)) { length = groundLength; hitUnit = NULL; hitFeature = NULL; } return length; }
void CFeatureHandler::LoadFeaturesFromMap(CFileHandler* file,bool onlyCreateDefs) { file->Seek(readmap->header.featurePtr); MapFeatureHeader fh; READ_MAPFEATUREHEADER(fh, file); if(file->Eof()){ info->AddLine("No features in map file?"); return; } string* mapids=new string[fh.numFeatureType]; for(int a=0;a<fh.numFeatureType;++a){ char c; file->Read(&c,1); while(c){ mapids[a]+=c; file->Read(&c,1); } string name=mapids[a]; if(name.find("TreeType")!=string::npos){ FeatureDef* fd=new FeatureDef; fd->blocking=1; fd->burnable=true; fd->destructable=1; fd->drawType=DRAWTYPE_TREE; fd->modelType=atoi(name.substr(8).c_str()); fd->energy=250; fd->metal=0; fd->maxHealth=5; fd->radius=20; fd->xsize=2; fd->ysize=2; fd->myName=name; fd->mass=20; featureDefs[name]=fd; } else if(name.find("GeoVent")!=string::npos){ FeatureDef* fd=new FeatureDef; fd->blocking=0; fd->burnable=0; fd->destructable=0; fd->geoThermal=1; fd->drawType=DRAWTYPE_NONE; //geos are drawn into the ground texture and emit smoke to be visible fd->modelType=0; fd->energy=0; fd->metal=0; fd->maxHealth=0; fd->radius=0; fd->xsize=0; fd->ysize=0; fd->myName=name; fd->mass=100000; featureDefs[name]=fd; } else if(wreckParser.SectionExist(name)){ GetFeatureDef(name); } else { info->AddLine("Unknown feature type %s",name.c_str()); } } if(!onlyCreateDefs){ for(int a=0;a<fh.numFeatures;++a){ MapFeatureStruct ffs; READ_MAPFEATURESTRUCT(ffs, file); string name=mapids[ffs.featureType]; ffs.ypos=ground->GetHeight2(ffs.xpos,ffs.zpos); CFeature *f = new CFeature; f->Initialize (float3(ffs.xpos,ffs.ypos,ffs.zpos),featureDefs[name],(short int)ffs.rotation,-1,""); } } delete[] mapids; }
float GuiTraceRay(const float3 &start, const float3 &dir, float length, bool useRadar, const CUnit* exclude, CUnit*& hitUnit, CFeature*& hitFeature) { hitUnit = NULL; hitFeature = NULL; if (dir == ZeroVector) { return -1.0f; } bool hover_factory = false; CollisionQuery cq; { GML_RECMUTEX_LOCK(quad); //! GuiTraceRay const vector<int> &quads = qf->GetQuadsOnRay(start, dir, length); std::list<CUnit*>::const_iterator ui; std::list<CFeature*>::const_iterator fi; for (vector<int>::const_iterator qi = quads.begin(); qi != quads.end(); ++qi) { const CQuadField::Quad& quad = qf->GetQuad(*qi); //! Unit Intersection for (ui = quad.units.begin(); ui != quad.units.end(); ++ui) { CUnit* unit = *ui; if (unit == exclude) { continue; } if ((unit->allyteam == gu->myAllyTeam) || gu->spectatingFullView || (unit->losStatus[gu->myAllyTeam] & (LOS_INLOS | LOS_CONTRADAR)) || (useRadar && radarhandler->InRadar(unit, gu->myAllyTeam))) { CollisionVolume cv(unit->collisionVolume); if (unit->isIcon) { //! for iconified units, just pretend the collision //! volume is a sphere of radius <unit->IconRadius> cv.Init(unit->iconRadius); } if (CCollisionHandler::MouseHit(unit, start, start + dir * length, &cv, &cq)) { //! get the distance to the ray-volume ingress point const float3& intPos = (cq.b0)? cq.p0 : cq.p1; const float len = (intPos - start).dot(dir); //! same as (intPos - start).Length() const bool isfactory = dynamic_cast<CFactory*>(unit); if (len < length) { if (!isfactory || !hitUnit || hover_factory) { hover_factory = isfactory; length = len; hitUnit = unit; hitFeature = NULL; } } else if (!isfactory && hover_factory) { //FIXME still check if the unit is BEHIND (and not IN) the factory! //! give an unit in a factory a higher priority than the factory itself hover_factory = isfactory; length = len; hitUnit = unit; hitFeature = NULL; } } } } //! Feature Intersection // NOTE: switch this to custom volumes fully? // (not used for any LOF checks, maybe wasteful) for (fi = quad.features.begin(); fi != quad.features.end(); ++fi) { CFeature* f = *fi; if (!f->collisionVolume) { continue; } //FIXME add useradar? if (!gu->spectatingFullView && !f->IsInLosForAllyTeam(gu->myAllyTeam)) { continue; } if (f->noSelect) { continue; } if (CCollisionHandler::Intersect(f, start, start + dir * length, &cq)) { const float3& intPos = (cq.b0)? cq.p0 : cq.p1; const float len = (intPos - start).dot(dir); //! same as (intPos - start).Length() //! we want the closest feature (intersection point) on the ray if (len < length) { hover_factory = false; length = len; hitFeature = f; hitUnit = NULL; } else if (hover_factory) { //FIXME still check if the unit is BEHIND (and not IN) the factory! //! give features in a factory a higher priority than the factory itself hover_factory = false; length = len; hitFeature = f; hitUnit = NULL; } } } } } //! ground intersection float groundLen = ground->LineGroundCol(start, start + dir * length); if (groundLen > 0.0f) { if (groundLen+200.0f < length) { length = groundLen; hitUnit = NULL; hitFeature = NULL; } } return length; }
Geodatabase::CFeature* CShapefileFeatureClass::ShpReadFeature(long index) { Geometry* pGeometry = NULL; pGeometry = ReadShape(index); CFeature *pFeature =new CFeature(this,index+1); pFeature->SetShape(pGeometry); for( int iField = 0; iField < m_allFields.size();iField++ ) { // Skip null fields. if( DBFIsAttributeNULL( m_dbfHandle, index, iField ) ) continue; switch( m_allFields[iField]->GetType()) { case Geodatabase::FTYPE_DATE: { const char* pszDateValue = DBFReadStringAttribute(m_dbfHandle,index,iField); pFeature->m_values[iField].vtype =Geodatabase::FieldValue::VT_DATE; if( pszDateValue[2] == '/' && pszDateValue[5] == '/' && strlen(pszDateValue) >= 10 ) { pFeature->m_values[iField].m_Var.date.Month =atoi(pszDateValue+0); pFeature->m_values[iField].m_Var.date.Day = atoi(pszDateValue+3); pFeature->m_values[iField].m_Var.date.Year = atoi(pszDateValue+6); } else { int nFullDate = atoi(pszDateValue); pFeature->m_values[iField].m_Var.date.Year = (int)(nFullDate / 10000); pFeature->m_values[iField].m_Var.date.Month = (unsigned char)((nFullDate / 100) % 100); pFeature->m_values[iField].m_Var.date.Day = (unsigned char)(nFullDate % 100); } break; } case Geodatabase::FTYPE_STRING: pFeature->m_values[iField].SetString(DBFReadStringAttribute(m_dbfHandle, index,iField )); break; case Geodatabase::FTYPE_LONG: pFeature->m_values[iField].vtype =FieldValue::VT_INT; pFeature->m_values[iField].m_Var.iVal =DBFReadIntegerAttribute(m_dbfHandle, index,iField ); break; case Geodatabase::FTYPE_FLOAT: case Geodatabase::FTYPE_DOUBLE: pFeature->m_values[iField].vtype =FieldValue::VT_DOUBLE; pFeature->m_values[iField].m_Var.dVal =DBFReadDoubleAttribute(m_dbfHandle, index,iField ); break; default: break; } } return pFeature; }
void DrawQuad(int x, int y) { std::vector<IWorldObjectModelRenderer*>& opaqueModelRenderers = featureDrawer->opaqueModelRenderers; std::vector<IWorldObjectModelRenderer*>& cloakedModelRenderers = featureDrawer->cloakedModelRenderers; const CFeatureDrawer::DrawQuad* dq = &(*drawQuads)[y * drawQuadsX + x]; for (std::set<CFeature*>::const_iterator fi = dq->features.begin(); fi != dq->features.end(); ++fi) { CFeature* f = (*fi); if (f->IsInVoid()) continue; assert(f->def->drawType == DRAWTYPE_MODEL); if (gu->spectatingFullView || f->IsInLosForAllyTeam(gu->myAllyTeam)) { if (drawReflection) { float3 zeroPos; if (f->midPos.y < 0.0f) { zeroPos = f->midPos; } else { const float dif = f->midPos.y - camera->GetPos().y; zeroPos = camera->GetPos() * (f->midPos.y / dif) + f->midPos * (-camera->GetPos().y / dif); } if (ground->GetApproximateHeight(zeroPos.x, zeroPos.z, false) > f->drawRadius) { continue; } } if (drawRefraction) { if (f->pos.y > 0.0f) continue; } const float sqDist = (f->pos - camera->GetPos()).SqLength(); const float farLength = f->sqRadius * unitDrawer->unitDrawDistSqr; #ifdef USE_GML if (statFeatures && (f->reclaimLeft < 1.0f || f->resurrectProgress > 0.0f)) statFeatures->push_back(f); #endif if (sqDist < farLength) { float sqFadeDistE; float sqFadeDistB; if (farLength < sqFadeDistEnd) { sqFadeDistE = farLength; sqFadeDistB = farLength * sqFadeDistBegin / sqFadeDistEnd; } else { sqFadeDistE = sqFadeDistEnd; sqFadeDistB = sqFadeDistBegin; } if (sqDist < sqFadeDistB) { cloakedModelRenderers[MDL_TYPE(f)]->DelFeature(f); if (camera->InView(f->drawMidPos, f->drawRadius)) opaqueModelRenderers[MDL_TYPE(f)]->AddFeature(f); } else if (sqDist < sqFadeDistE) { const float falpha = 1.0f - (sqDist - sqFadeDistB) / (sqFadeDistE - sqFadeDistB); opaqueModelRenderers[MDL_TYPE(f)]->DelFeature(f); if (camera->InView(f->drawMidPos, f->drawRadius)) cloakedModelRenderers[MDL_TYPE(f)]->AddFeature(f, falpha); } } else { if (farFeatures) { farTextureHandler->Queue(f); } } } } }
// FOR SYNCED MESSAGES void CGame::ActionReceived(const Action& action, int playernum) { if (action.command == "cheat") { SetBoolArg(gs->cheatEnabled, action.extra); if (gs->cheatEnabled) logOutput.Print("Cheating!"); else logOutput.Print("No more cheating"); } else if (action.command == "nohelp") { SetBoolArg(gs->noHelperAIs, action.extra); selectedUnits.PossibleCommandChange(NULL); logOutput.Print("LuaUI control is %s", gs->noHelperAIs ? "disabled" : "enabled"); } else if (action.command == "nospecdraw") { bool buf; SetBoolArg(buf, action.extra); inMapDrawer->SetSpecMapDrawingAllowed(buf); } else if (action.command == "godmode") { if (!gs->cheatEnabled) logOutput.Print("godmode requires /cheat"); else { SetBoolArg(gs->godMode, action.extra); CLuaUI::UpdateTeams(); if (gs->godMode) { logOutput.Print("God Mode Enabled"); } else { logOutput.Print("God Mode Disabled"); } CPlayer::UpdateControlledTeams(); } } else if (action.command == "globallos") { if (!gs->cheatEnabled) { logOutput.Print("globallos requires /cheat"); } else { SetBoolArg(gs->globalLOS, action.extra); if (gs->globalLOS) { logOutput.Print("Global LOS Enabled"); } else { logOutput.Print("Global LOS Disabled"); } } } else if (action.command == "nocost" && gs->cheatEnabled) { if (unitDefHandler->ToggleNoCost()) { logOutput.Print("Everything is for free!"); } else { logOutput.Print("Everything costs resources again!"); } } else if (action.command == "give" && gs->cheatEnabled) { std::string s = "give "; //FIXME lazyness s += action.extra; // .give [amount] <unitName> [team] <@x,y,z> const vector<string> &args = CSimpleParser::Tokenize(s, 0); if (args.size() < 3) { logOutput.Print("Someone is spoofing invalid .give messages!"); return; } float3 pos; if (sscanf(args[args.size() - 1].c_str(), "@%f,%f,%f", &pos.x, &pos.y, &pos.z) != 3) { logOutput.Print("Someone is spoofing invalid .give messages!"); return; } int amount = 1; int team = playerHandler->Player(playernum)->team; int amountArgIdx = -1; int teamArgIdx = -1; if (args.size() == 5) { amountArgIdx = 1; teamArgIdx = 3; } else if (args.size() == 4) { if (args[1].find_first_not_of("0123456789") == string::npos) { amountArgIdx = 1; } else { teamArgIdx = 2; } } if (amountArgIdx >= 0) { const string& amountStr = args[amountArgIdx]; amount = atoi(amountStr.c_str()); if ((amount < 0) || (amountStr.find_first_not_of("0123456789") != string::npos)) { logOutput.Print("Bad give amount: %s", amountStr.c_str()); return; } } if (teamArgIdx >= 0) { const string& teamStr = args[teamArgIdx]; team = atoi(teamStr.c_str()); if ((!teamHandler->IsValidTeam(team)) || (teamStr.find_first_not_of("0123456789") != string::npos)) { logOutput.Print("Bad give team: %s", teamStr.c_str()); return; } } const string unitName = (amountArgIdx >= 0) ? args[2] : args[1]; if (unitName == "all") { // player entered ".give all" int numRequestedUnits = unitDefHandler->unitDefs.size() - 1; /// defid=0 is not valid int currentNumUnits = teamHandler->Team(team)->units.size(); int sqSize = (int) streflop::ceil(streflop::sqrt((float) numRequestedUnits)); // make sure team unit-limit not exceeded if ((currentNumUnits + numRequestedUnits) > uh->MaxUnitsPerTeam()) { numRequestedUnits = uh->MaxUnitsPerTeam() - currentNumUnits; } // make sure square is entirely on the map float sqHalfMapSize = sqSize / 2 * 10 * SQUARE_SIZE; pos.x = std::max(sqHalfMapSize, std::min(pos.x, float3::maxxpos - sqHalfMapSize - 1)); pos.z = std::max(sqHalfMapSize, std::min(pos.z, float3::maxzpos - sqHalfMapSize - 1)); for (int a = 1; a <= numRequestedUnits; ++a) { float posx = pos.x + (a % sqSize - sqSize / 2) * 10 * SQUARE_SIZE; float posz = pos.z + (a / sqSize - sqSize / 2) * 10 * SQUARE_SIZE; float3 pos2 = float3(posx, pos.y, posz); const UnitDef* ud = unitDefHandler->GetUnitDefByID(a); if (ud) { const CUnit* unit = unitLoader->LoadUnit(ud, pos2, team, false, 0, NULL); if (unit) { unitLoader->FlattenGround(unit); } } } } else if (!unitName.empty()) { int numRequestedUnits = amount; int currentNumUnits = teamHandler->Team(team)->units.size(); if (currentNumUnits >= uh->MaxUnitsPerTeam()) { LogObject() << "Unable to give any more units to team " << team << "(current: " << currentNumUnits << ", max: " << uh->MaxUnits() << ")"; return; } // make sure team unit-limit is not exceeded if ((currentNumUnits + numRequestedUnits) > uh->MaxUnitsPerTeam()) { numRequestedUnits = uh->MaxUnitsPerTeam() - currentNumUnits; } const UnitDef* unitDef = unitDefHandler->GetUnitDefByName(unitName); if (unitDef != NULL) { int xsize = unitDef->xsize; int zsize = unitDef->zsize; int squareSize = (int) streflop::ceil(streflop::sqrt((float) numRequestedUnits)); int total = numRequestedUnits; float3 minpos = pos; minpos.x -= ((squareSize - 1) * xsize * SQUARE_SIZE) / 2; minpos.z -= ((squareSize - 1) * zsize * SQUARE_SIZE) / 2; for (int z = 0; z < squareSize; ++z) { for (int x = 0; x < squareSize && total > 0; ++x) { float minposx = minpos.x + x * xsize * SQUARE_SIZE; float minposz = minpos.z + z * zsize * SQUARE_SIZE; const float3 upos(minposx, minpos.y, minposz); const CUnit* unit = unitLoader->LoadUnit(unitDef, upos, team, false, 0, NULL); if (unit) { unitLoader->FlattenGround(unit); } --total; } } logOutput.Print("Giving %i %s to team %i", numRequestedUnits, unitName.c_str(), team); } else { int allyteam = -1; if (teamArgIdx < 0) { team = -1; // default to world features allyteam = -1; } else { allyteam = teamHandler->AllyTeam(team); } const FeatureDef* featureDef = featureHandler->GetFeatureDef(unitName); if (featureDef) { int xsize = featureDef->xsize; int zsize = featureDef->zsize; int squareSize = (int) streflop::ceil(streflop::sqrt((float) numRequestedUnits)); int total = amount; // FIXME -- feature count limit? float3 minpos = pos; minpos.x -= ((squareSize - 1) * xsize * SQUARE_SIZE) / 2; minpos.z -= ((squareSize - 1) * zsize * SQUARE_SIZE) / 2; for (int z = 0; z < squareSize; ++z) { for (int x = 0; x < squareSize && total > 0; ++x) { float minposx = minpos.x + x * xsize * SQUARE_SIZE; float minposz = minpos.z + z * zsize * SQUARE_SIZE; float minposy = ground->GetHeightReal(minposx, minposz); const float3 upos(minposx, minposy, minposz); CFeature* feature = new CFeature(); // Initialize() adds the feature to the FeatureHandler -> no memory-leak feature->Initialize(upos, featureDef, 0, 0, team, allyteam, ""); --total; } } logOutput.Print("Giving %i %s (feature) to team %i", numRequestedUnits, unitName.c_str(), team); } else { logOutput.Print(unitName + " is not a valid unitname"); } } } } else if (action.command == "destroy" && gs->cheatEnabled) { std::stringstream ss(action.extra); logOutput.Print("Killing units: %s", action.extra.c_str()); do { unsigned id; ss >> id; if (!ss) break; if (id >= uh->units.size()) continue; if (uh->units[id] == NULL) continue; uh->units[id]->KillUnit(false, false, 0); } while (true); }
int CAICallback::HandleCommand(int commandId, void* data) { switch (commandId) { case AIHCQuerySubVersionId: { return 1; // current version of Handle Command interface } break; case AIHCAddMapPointId: { const AIHCAddMapPoint* cmdData = static_cast<AIHCAddMapPoint*>(data); net->Send(CBaseNetProtocol::Get().SendMapDrawPoint(team, (short)cmdData->pos.x, (short)cmdData->pos.z, std::string(cmdData->label), false)); return 1; } break; case AIHCAddMapLineId: { const AIHCAddMapLine* cmdData = static_cast<AIHCAddMapLine*>(data); net->Send(CBaseNetProtocol::Get().SendMapDrawLine(team, (short)cmdData->posfrom.x, (short)cmdData->posfrom.z, (short)cmdData->posto.x, (short)cmdData->posto.z, false)); return 1; } break; case AIHCRemoveMapPointId: { const AIHCRemoveMapPoint* cmdData = static_cast<AIHCRemoveMapPoint*>(data); net->Send(CBaseNetProtocol::Get().SendMapErase(team, (short)cmdData->pos.x, (short)cmdData->pos.z)); return 1; } break; case AIHCSendStartPosId: { const AIHCSendStartPos* cmdData = static_cast<AIHCSendStartPos*>(data); SendStartPos(cmdData->ready, cmdData->pos); return 1; } break; case AIHCGetUnitDefByIdId: { // NOTE: this command should never arrive, handled in SSkirmishAICallbackImpl return 0; } break; case AIHCGetWeaponDefByIdId: { // NOTE: this command should never arrive, handled in SSkirmishAICallbackImpl return 0; } break; case AIHCGetFeatureDefByIdId: { // NOTE: this command should never arrive, handled in SSkirmishAICallbackImpl return 0; } break; case AIHCTraceRayId: { AIHCTraceRay* cmdData = static_cast<AIHCTraceRay*>(data); if (CHECK_UNITID(cmdData->srcUID)) { const CUnit* srcUnit = unitHandler->units[cmdData->srcUID]; if (srcUnit != NULL) { CUnit* hitUnit = NULL; CFeature* hitFeature = NULL; //FIXME add COLLISION_NOFEATURE? const float realLen = TraceRay::TraceRay(cmdData->rayPos, cmdData->rayDir, cmdData->rayLen, cmdData->flags, srcUnit, hitUnit, hitFeature); if (hitUnit != NULL) { myAllyTeamId = teamHandler->AllyTeam(team); const bool isUnitVisible = unit_IsInLos(hitUnit); if (isUnitVisible) { cmdData->rayLen = realLen; cmdData->hitUID = hitUnit->id; } } } } return 1; } break; case AIHCFeatureTraceRayId: { AIHCFeatureTraceRay* cmdData = static_cast<AIHCFeatureTraceRay*>(data); if (CHECK_UNITID(cmdData->srcUID)) { const CUnit* srcUnit = unitHandler->units[cmdData->srcUID]; if (srcUnit != NULL) { CUnit* hitUnit = NULL; CFeature* hitFeature = NULL; //FIXME add COLLISION_NOENEMIES || COLLISION_NOFRIENDLIES || COLLISION_NONEUTRALS? const float realLen = TraceRay::TraceRay(cmdData->rayPos, cmdData->rayDir, cmdData->rayLen, cmdData->flags, srcUnit, hitUnit, hitFeature); if (hitFeature != NULL) { const bool isFeatureVisible = hitFeature->IsInLosForAllyTeam(teamHandler->AllyTeam(team)); if (isFeatureVisible) { cmdData->rayLen = realLen; cmdData->hitFID = hitFeature->id; } } } } return 1; } break; case AIHCPauseId: { AIHCPause* cmdData = static_cast<AIHCPause*>(data); net->Send(CBaseNetProtocol::Get().SendPause(gu->myPlayerNum, cmdData->enable)); LOG("Skirmish AI controlling team %i paused the game, reason: %s", team, cmdData->reason != NULL ? cmdData->reason : "UNSPECIFIED"); return 1; } break; case AIHCGetDataDirId: { // do nothing // this event will never end up here, as // it is handled in the C layer directly // see Clb_DataDirs_allocatePath in rts/ExternalAI/Interface/SSkirmishAICallback.h return 0; } break; case AIHCDebugDrawId: { AIHCDebugDraw* cmdData = static_cast<AIHCDebugDraw*>(data); switch (cmdData->cmdMode) { case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_ADD_GRAPH_POINT: { debugDrawerAI->AddGraphPoint(this->team, cmdData->lineId, cmdData->x, cmdData->y); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_DEL_GRAPH_POINTS: { debugDrawerAI->DelGraphPoints(this->team, cmdData->lineId, cmdData->numPoints); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_SET_GRAPH_POS: { debugDrawerAI->SetGraphPos(this->team, cmdData->x, cmdData->y); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_SET_GRAPH_SIZE: { debugDrawerAI->SetGraphSize(this->team, cmdData->w, cmdData->h); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_SET_GRAPH_LINE_COLOR: { debugDrawerAI->SetGraphLineColor(this->team, cmdData->lineId, cmdData->color); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_SET_GRAPH_LINE_LABEL: { debugDrawerAI->SetGraphLineLabel(this->team, cmdData->lineId, cmdData->label); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_ADD_OVERLAY_TEXTURE: { cmdData->texHandle = debugDrawerAI->AddOverlayTexture( this->team, cmdData->texData, int(cmdData->w), // interpret as absolute width int(cmdData->h) // interpret as absolute height ); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_UPDATE_OVERLAY_TEXTURE: { debugDrawerAI->UpdateOverlayTexture( this->team, cmdData->texHandle, cmdData->texData, int(cmdData->x), // interpret as absolute pixel col int(cmdData->y), // interpret as absolute pixel row int(cmdData->w), // interpret as absolute width int(cmdData->h) // interpret as absolute height ); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_DEL_OVERLAY_TEXTURE: { debugDrawerAI->DelOverlayTexture(this->team, cmdData->texHandle); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_SET_OVERLAY_TEXTURE_POS: { debugDrawerAI->SetOverlayTexturePos(this->team, cmdData->texHandle, cmdData->x, cmdData->y); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_SET_OVERLAY_TEXTURE_SIZE: { debugDrawerAI->SetOverlayTextureSize(this->team, cmdData->texHandle, cmdData->w, cmdData->h); } break; case AIHCDebugDraw::AIHC_DEBUGDRAWER_MODE_SET_OVERLAY_TEXTURE_LABEL: { debugDrawerAI->SetOverlayTextureLabel(this->team, cmdData->texHandle, cmdData->label); } break; default: { } break; } return 1; } break; default: { return 0; } } }
float GuiTraceRay( const float3& start, const float3& dir, const float length, const CUnit* exclude, CUnit*& hitUnit, CFeature*& hitFeature, bool useRadar, bool groundOnly, bool ignoreWater ) { hitUnit = NULL; hitFeature = NULL; if (dir == ZeroVector) return -1.0f; // ground intersection const float guiRayLength = length; const float groundRayLength = ground->LineGroundCol(start, start + dir * guiRayLength, false); const float waterRayLength = math::floor(math::fabs(start.y / std::min(dir.y, -0.00001f))); float minRayLength = groundRayLength; float minIngressDist = length; float minEgressDist = length; if (!ignoreWater) minRayLength = std::min(groundRayLength, waterRayLength); if (groundOnly) return minRayLength; GML_RECMUTEX_LOCK(quad); // GuiTraceRay int* begQuad = NULL; int* endQuad = NULL; bool hitFactory = false; CollisionQuery cq; quadField->GetQuadsOnRay(start, dir, length, begQuad, endQuad); std::list<CUnit*>::const_iterator ui; std::list<CFeature*>::const_iterator fi; for (int* quadPtr = begQuad; quadPtr != endQuad; ++quadPtr) { const CQuadField::Quad& quad = quadField->GetQuad(*quadPtr); // Unit Intersection for (ui = quad.units.begin(); ui != quad.units.end(); ++ui) { CUnit* unit = *ui; const bool unitIsEnemy = !teamHandler->Ally(unit->allyteam, gu->myAllyTeam); const bool unitOnRadar = (useRadar && radarhandler->InRadar(unit, gu->myAllyTeam)); const bool unitInSight = (unit->losStatus[gu->myAllyTeam] & (LOS_INLOS | LOS_CONTRADAR)); const bool unitVisible = !unitIsEnemy || unitOnRadar || unitInSight || gu->spectatingFullView; if (unit == exclude) continue; if (!unitVisible) continue; CollisionVolume cv(unit->collisionVolume); if (unit->isIcon || (!unitInSight && unitOnRadar && unitIsEnemy)) { // for iconified units, just pretend the collision // volume is a sphere of radius <unit->IconRadius> // (count radar blips as such too) cv.InitSphere(unit->iconRadius); } if (CCollisionHandler::MouseHit(unit, start, start + dir * guiRayLength, &cv, &cq)) { // get the distance to the ray-volume ingress point // (not likely to generate inside-hit special cases) const float ingressDist = cq.GetIngressPosDist(start, dir); const float egressDist = cq.GetEgressPosDist(start, dir); const bool isFactory = unit->unitDef->IsFactoryUnit(); const bool factoryHitBeforeUnit = ((hitFactory && ingressDist < minIngressDist) || (!hitFactory && egressDist < minIngressDist)); const bool unitHitInsideFactory = ((hitFactory && ingressDist < minEgressDist) || (!hitFactory && ingressDist < minIngressDist)); // give units in a factory higher priority than the factory itself if (hitUnit == NULL || (isFactory && factoryHitBeforeUnit) || (!isFactory && unitHitInsideFactory)) { hitFactory = isFactory; minIngressDist = ingressDist; minEgressDist = egressDist; hitUnit = unit; hitFeature = NULL; } } } // Feature Intersection // NOTE: switch this to custom volumes fully? // (not used for any LOF checks, maybe wasteful) for (fi = quad.features.begin(); fi != quad.features.end(); ++fi) { CFeature* f = *fi; // FIXME add useradar? if (!gu->spectatingFullView && !f->IsInLosForAllyTeam(gu->myAllyTeam)) continue; if (f->noSelect) continue; if (CCollisionHandler::DetectHit(f, start, start + dir * guiRayLength, &cq, true)) { const float hitDist = cq.GetHitPosDist(start, dir); const bool factoryHitBeforeUnit = ( hitFactory && hitDist < minEgressDist); const bool unitHitInsideFactory = (!hitFactory && hitDist < minIngressDist); // we want the closest feature (intersection point) on the ray // give features in a factory (?) higher priority than the factory itself if (hitUnit == NULL || factoryHitBeforeUnit || unitHitInsideFactory) { hitFactory = false; minIngressDist = hitDist; hitFeature = f; hitUnit = NULL; } } } } if ((minRayLength > 0.0f) && ((minRayLength + 200.0f) < minIngressDist)) { minIngressDist = minRayLength; hitUnit = NULL; hitFeature = NULL; } return minIngressDist; }
void CUnitLoader::GiveUnits(const std::string& objectName, float3 pos, int amount, int team, int featureAllyTeam) { const CTeam* receivingTeam = teamHandler->Team(team); if (objectName == "all") { unsigned int numRequestedUnits = unitDefHandler->unitDefs.size() - 1; /// defid=0 is not valid unsigned int currentNumUnits = receivingTeam->units.size(); // make sure team unit-limit is not exceeded if ((currentNumUnits + numRequestedUnits) > receivingTeam->maxUnits) { numRequestedUnits = receivingTeam->maxUnits - currentNumUnits; } // make sure square is entirely on the map const int sqSize = math::ceil(math::sqrt((float) numRequestedUnits)); const float sqHalfMapSize = sqSize / 2 * 10 * SQUARE_SIZE; pos.x = std::max(sqHalfMapSize, std::min(pos.x, float3::maxxpos - sqHalfMapSize - 1)); pos.z = std::max(sqHalfMapSize, std::min(pos.z, float3::maxzpos - sqHalfMapSize - 1)); for (int a = 1; a <= numRequestedUnits; ++a) { Watchdog::ClearPrimaryTimers(); // the other thread may be waiting for a mutex held by this one, triggering hang detection const float px = pos.x + (a % sqSize - sqSize / 2) * 10 * SQUARE_SIZE; const float pz = pos.z + (a / sqSize - sqSize / 2) * 10 * SQUARE_SIZE; const float3 unitPos = float3(px, ground->GetHeightReal(px, pz), pz); const UnitDef* unitDef = unitDefHandler->GetUnitDefByID(a); if (unitDef != NULL) { const CUnit* unit = LoadUnit(unitDef, unitPos, team, false, 0, NULL); if (unit != NULL) { FlattenGround(unit); } } } } else { unsigned int numRequestedUnits = amount; unsigned int currentNumUnits = receivingTeam->units.size(); if (receivingTeam->AtUnitLimit()) { LOG_L(L_WARNING, "[%s] unable to give more units to team %d (current: %u, team limit: %u, global limit: %u)", __FUNCTION__, team, currentNumUnits, receivingTeam->maxUnits, uh->MaxUnits() ); return; } // make sure team unit-limit is not exceeded if ((currentNumUnits + numRequestedUnits) > receivingTeam->maxUnits) { numRequestedUnits = receivingTeam->maxUnits - currentNumUnits; } const UnitDef* unitDef = unitDefHandler->GetUnitDefByName(objectName); const FeatureDef* featureDef = featureHandler->GetFeatureDef(objectName, false); if (unitDef == NULL && featureDef == NULL) { LOG_L(L_WARNING, "[%s] %s is not a valid object-name", __FUNCTION__, objectName.c_str()); return; } if (unitDef != NULL) { const int xsize = unitDef->xsize; const int zsize = unitDef->zsize; const int squareSize = math::ceil(math::sqrt((float) numRequestedUnits)); const float3 squarePos = float3( pos.x - (((squareSize - 1) * xsize * SQUARE_SIZE) / 2), pos.y, pos.z - (((squareSize - 1) * zsize * SQUARE_SIZE) / 2) ); int total = numRequestedUnits; for (int z = 0; z < squareSize; ++z) { for (int x = 0; x < squareSize && total > 0; ++x) { const float px = squarePos.x + x * xsize * SQUARE_SIZE; const float pz = squarePos.z + z * zsize * SQUARE_SIZE; const float3 unitPos = float3(px, ground->GetHeightReal(px, pz), pz); Watchdog::ClearPrimaryTimers(); const CUnit* unit = LoadUnit(unitDef, unitPos, team, false, 0, NULL); if (unit != NULL) { FlattenGround(unit); } --total; } } LOG("[%s] spawned %i %s unit(s) for team %i", __FUNCTION__, numRequestedUnits, objectName.c_str(), team); } if (featureDef != NULL) { if (featureAllyTeam < 0) { team = -1; // default to world features } const int xsize = featureDef->xsize; const int zsize = featureDef->zsize; const int squareSize = math::ceil(math::sqrt((float) numRequestedUnits)); const float3 squarePos = float3( pos.x - (((squareSize - 1) * xsize * SQUARE_SIZE) / 2), pos.y, pos.z - (((squareSize - 1) * zsize * SQUARE_SIZE) / 2) ); int total = amount; // FIXME -- feature count limit? for (int z = 0; z < squareSize; ++z) { for (int x = 0; x < squareSize && total > 0; ++x) { const float px = squarePos.x + x * xsize * SQUARE_SIZE; const float pz = squarePos.z + z * zsize * SQUARE_SIZE; const float3 featurePos = float3(px, ground->GetHeightReal(px, pz), pz); Watchdog::ClearPrimaryTimers(); CFeature* feature = new CFeature(); // Initialize() adds the feature to the FeatureHandler -> no memory-leak feature->Initialize(featurePos, featureDef, 0, 0, team, featureAllyTeam, NULL); --total; } } LOG("[%s] spawned %i %s feature(s) for team %i", __FUNCTION__, numRequestedUnits, objectName.c_str(), team); } } }