コード例 #1
0
ファイル: UnitHandler.cpp プロジェクト: imbaczek/spring
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;
}
コード例 #2
0
ファイル: GameHelper.cpp プロジェクト: javaphoon/spring
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;
}
コード例 #3
0
ファイル: GameHelper.cpp プロジェクト: AlexDiede/spring
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;
}
コード例 #4
0
ファイル: FeatureDrawer.cpp プロジェクト: AMDmi3/spring
	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);
					}
				}
			}
		}
	}
コード例 #5
0
ファイル: AICallback.cpp プロジェクト: AlexDiede/spring
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;
		}
	}
}
コード例 #6
0
ファイル: TraceRay.cpp プロジェクト: Finkky/spring
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;
}
コード例 #7
0
ファイル: TraceRay.cpp プロジェクト: KellyMahan/spring
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;
}
コード例 #8
0
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);
			}
		}
	}
}
コード例 #9
0
ファイル: TraceRay.cpp プロジェクト: AlexDiede/spring
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;
}
コード例 #10
0
ファイル: AICallback.cpp プロジェクト: nixtux/spring
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;
		}
	}
}