minimap.cpp

来自「这是整套横扫千军3D版游戏的源码」· C++ 代码 · 共 1,537 行 · 第 1/3 页

CPP
1,537
字号
		ProxyMouseRelease(x, y, button);
		proxyMode = false;
		return;
	}

	if (selecting) {
		SelectUnits(x, y);
		selecting = false;
		return;
	}

	if (button == SDL_BUTTON_LEFT) {
		if (showButtons && maximizeBox.Inside(x, y)) {
			ToggleMaximized(!!keys[SDLK_LSHIFT]);
			return;
		}

		if (showButtons && minimizeBox.Inside(x, y)) {
			minimized = true;
			return;
		}
	}
}


void CMiniMap::SetGeometry(int px, int py, int sx, int sy)
{
	xpos = px;
	ypos = py;
	width = sx;
	height = sy;
	UpdateGeometry();
}


void CMiniMap::UpdateGeometry()
{
	// keep the same distance to the top
	ypos -= (lastWindowSizeY - gu->viewSizeY);
	if (gu->dualScreenMode) {
		width = gu->viewSizeX;
		height = gu->viewSizeY;
		xpos = (gu->viewSizeX - gu->viewPosX);
		ypos = 0;
	}
	else if (maximized) {
		SetMaximizedGeometry();
	}
	else {
		width = max(1, min(width, gu->viewSizeX));
		height = max(1, min(height, gu->viewSizeY));
		ypos = max(slaveDrawMode ? 0 : buttonSize, ypos);
		ypos = min(gu->viewSizeY - height, ypos);
		xpos = max(0, min(gu->viewSizeX - width, xpos));
	}
	lastWindowSizeX = gu->viewSizeX;
	lastWindowSizeY = gu->viewSizeY;

	// setup the unit scaling
	const float w = float(width);
	const float h = float(height);
	const float mapx = float(gs->mapx * SQUARE_SIZE);
	const float mapy = float(gs->mapy * SQUARE_SIZE);
	const float ref  = unitBaseSize / powf((200.f * 200.0f), unitExponent);
	const float dpr  = ref * powf((w * h), unitExponent);

	unitSizeX = dpr * (mapx / w);
	unitSizeY = dpr * (mapy / h);
	unitSelectRadius = sqrtf(unitSizeX * unitSizeY);

	// in mouse coordinates
	mapBox.xmin = xpos;
	mapBox.xmax = mapBox.xmin + width - 1;
	mapBox.ymin = gu->viewSizeY - (ypos + height);
	mapBox.ymax = mapBox.ymin + height - 1;

	if (!maximized) {
		// right to left
		resizeBox.xmax   = mapBox.xmax;
		resizeBox.xmin   = resizeBox.xmax - (buttonSize - 1);
		moveBox.xmax     = resizeBox.xmax   - buttonSize;
		moveBox.xmin     = resizeBox.xmin   - buttonSize;
		maximizeBox.xmax = moveBox.xmax     - buttonSize;
		maximizeBox.xmin = moveBox.xmin     - buttonSize;
		minimizeBox.xmax = maximizeBox.xmax - buttonSize;
		minimizeBox.xmin = maximizeBox.xmin - buttonSize;
		const int ymin = (mapBox.ymax + 1) + 3; // 3 for the white|black|white
		const int ymax = ymin + (buttonSize - 1);
		resizeBox.ymin = moveBox.ymin = maximizeBox.ymin = minimizeBox.ymin = ymin;
		resizeBox.ymax = moveBox.ymax = maximizeBox.ymax = minimizeBox.ymax = ymax;
		buttonBox.xmin = minimizeBox.xmin;
		buttonBox.xmax = mapBox.xmax;
		buttonBox.ymin = ymin - 3;
		buttonBox.ymax = ymax;
	} else {
		// left to right
		minimizeBox.xmin = mapBox.xmin;
		minimizeBox.xmax = minimizeBox.xmin + (buttonSize - 1);
		maximizeBox.xmin = minimizeBox.xmin + buttonSize;
		maximizeBox.xmax = minimizeBox.xmax + buttonSize;
		// dead buttons
		resizeBox.xmin = resizeBox.ymin = moveBox.xmin = moveBox.ymin = 0;
		resizeBox.xmax = resizeBox.ymax = moveBox.xmax = moveBox.ymax = -1;
		const int ymin = mapBox.ymin;
		const int ymax = ymin + (buttonSize - 1);
		maximizeBox.ymin = minimizeBox.ymin = ymin;
		maximizeBox.ymax = minimizeBox.ymax = ymax;
		buttonBox.xmin = minimizeBox.xmin;
		buttonBox.xmax = maximizeBox.xmax;
		buttonBox.ymin = ymin - 3;
		buttonBox.ymax = ymax;
	}
}


/******************************************************************************/

void CMiniMap::MoveView(int x, int y)
{
	const float3& pos = camera->pos;
	const float3& dir = camera->forward;
	float dist = ground->LineGroundCol(pos, pos + (dir * gu->viewRange * 1.4f));
	float3 dif(0,0,0);
	if (dist > 0) {
		dif = dir * dist;
	}
	float3 clickPos;
	clickPos.x = (float(x - xpos)) / width * gs->mapx * 8;
	clickPos.z = (float(y - (gu->viewSizeY - ypos - height))) / height * gs->mapy * 8;
	camCtrl->SetPos(clickPos);
	unitTracker.Disable();
}


void CMiniMap::SelectUnits(int x, int y) const
{
	if (!keys[SDLK_LSHIFT] && !keys[SDLK_LCTRL]) {
		selectedUnits.ClearSelected();
	}

	CMouseHandler::ButtonPress& bp = mouse->buttons[SDL_BUTTON_LEFT];

	if (fullProxy && (bp.movement > 4)) {
		// use a selection box
		const float3 newPos = GetMapPosition(x, y);
		const float3 oldPos = GetMapPosition(bp.x, bp.y);
		const float xmin = min(oldPos.x, newPos.x);
		const float xmax = max(oldPos.x, newPos.x);
		const float zmin = min(oldPos.z, newPos.z);
		const float zmax = max(oldPos.z, newPos.z);

		CUnitSet::iterator ui;
		CUnitSet& selection = selectedUnits.selectedUnits;

		CUnit* unit = NULL;
		int addedunits = 0;
		int team, lastTeam;

		if (gu->spectatingFullSelect) {
			team = 0;
			lastTeam = gs->activeTeams - 1;
		} else {
			team = gu->myTeam;
			lastTeam = gu->myTeam;
		}
		for (; team <= lastTeam; team++) {
			CUnitSet& teamUnits = gs->Team(team)->units;
			for (ui = teamUnits.begin(); ui != teamUnits.end(); ++ui) {
				const float3& midPos = (*ui)->midPos;

				if ((midPos.x > xmin) && (midPos.x < xmax) &&
					(midPos.z > zmin) && (midPos.z < zmax)) {

					if (keys[SDLK_LCTRL] && (selection.find(*ui) != selection.end())) {
						selectedUnits.RemoveUnit(*ui);
					} else {
						selectedUnits.AddUnit(*ui);
						unit = *ui;
						addedunits++;
					}
				}
			}
		}

		if (addedunits >= 2) {
			sound->PlaySample(mouse->soundMultiselID);
		}
		else if (addedunits == 1) {
			int soundIdx = unit->unitDef->sounds.select.getRandomIdx();
			if (soundIdx >= 0) {
				sound->PlayUnitReply(
					unit->unitDef->sounds.select.getID(soundIdx), unit,
					unit->unitDef->sounds.select.getVolume(soundIdx));
			}
		}
	}
	else {
		// Single unit
		const float size = unitSelectRadius;
		const float3 pos = GetMapPosition(x, y);

		CUnit* unit;
		if (gu->spectatingFullSelect) {
			unit = helper->GetClosestUnit(pos, size);
		} else {
			unit = helper->GetClosestFriendlyUnit(pos, size, gu->myAllyTeam);
		}

		CUnitSet::iterator ui;
		CUnitSet& selection = selectedUnits.selectedUnits;

		if (unit && ((unit->team == gu->myTeam) || gu->spectatingFullSelect)) {
			if (bp.lastRelease < (gu->gameTime - mouse->doubleClickTime)) {
				if (keys[SDLK_LCTRL] && (selection.find(unit) != selection.end())) {
					selectedUnits.RemoveUnit(unit);
				} else {
					selectedUnits.AddUnit(unit);
				}
			} else {
				//double click
				if (unit->group && !keys[SDLK_LCTRL]) {
					//select the current units group if it has one
					selectedUnits.SelectGroup(unit->group->id);
				} else {
					//select all units of same type
					int team, lastTeam;
					if (gu->spectatingFullSelect) {
						team = 0;
						lastTeam = gs->activeTeams - 1;
					} else {
						team = gu->myTeam;
						lastTeam = gu->myTeam;
					}
					for (; team <= lastTeam; team++) {
						CUnitSet& myUnits = gs->Team(team)->units;
						for (ui = myUnits.begin(); ui != myUnits.end(); ++ui) {
							if ((*ui)->aihint == unit->aihint) {
								selectedUnits.AddUnit(*ui);
							}
						}
					}
				}
			}
			bp.lastRelease = gu->gameTime;

			int soundIdx = unit->unitDef->sounds.select.getRandomIdx();
			if (soundIdx >= 0) {
				sound->PlayUnitReply(
					unit->unitDef->sounds.select.getID(soundIdx), unit,
					unit->unitDef->sounds.select.getVolume(soundIdx));
			}
		}
	}
}


/******************************************************************************/

CUnit* CMiniMap::GetSelectUnit(const float3& pos) const
{
	CUnit* unit = helper->GetClosestUnit(pos, unitSelectRadius);
	if (unit != NULL) {
		const int losMask = (LOS_INLOS | LOS_INRADAR);
		if ((unit->losStatus[gu->myAllyTeam] & losMask) || gu->spectatingFullView) {
			return unit;
		} else {
			return NULL;
		}
	}
	return unit;
}


float3 CMiniMap::GetMapPosition(int x, int y) const
{
	const float mapHeight = readmap->maxheight + 1000.0f;
	const float mapX = gs->mapx * SQUARE_SIZE;
	const float mapY = gs->mapy * SQUARE_SIZE;
	const float3 pos(mapX * float(x - xpos) / width, mapHeight,
	                 mapY * float(y - (gu->viewSizeY - ypos - height)) / height);
	return pos;
}


void CMiniMap::ProxyMousePress(int x, int y, int button)
{
	float3 mapPos = GetMapPosition(x, y);
	const CUnit* unit = GetSelectUnit(mapPos);
	if (unit) {
		if (gu->spectatingFullView) {
			mapPos = unit->midPos;
		} else {
			mapPos = helper->GetUnitErrorPos(unit, gu->myAllyTeam);
			mapPos.y = readmap->maxheight + 1000.0f;
		}
	}

	CMouseHandler::ButtonPress& bp = mouse->buttons[button];
	bp.camPos = mapPos;
	bp.dir = float3(0.0f, -1.0f, 0.0f);

	guihandler->MousePress(x, y, -button);
}


void CMiniMap::ProxyMouseRelease(int x, int y, int button)
{
	// is this really needed?
	CCamera *c = camera;
	camera = new CCamera(*c);

	const float3 tmpMouseDir = mouse->dir;

	float3 mapPos = GetMapPosition(x, y);
	const CUnit* unit = GetSelectUnit(mapPos);
	if (unit) {
		if (gu->spectatingFullView) {
			mapPos = unit->midPos;
		} else {
			mapPos = helper->GetUnitErrorPos(unit, gu->myAllyTeam);
			mapPos.y = readmap->maxheight + 1000.0f;
		}
	}

	mouse->dir = float3(0.0f, -1.0f, 0.0f);
	camera->pos = mapPos;
	camera->forward = mouse->dir;

	guihandler->MouseRelease(x, y, -button);

	mouse->dir = tmpMouseDir;
	delete camera;
	camera = c;
}


/******************************************************************************/

bool CMiniMap::IsAbove(int x, int y)
{
	if (minimized) {
		if ((x < buttonSize) && (y < buttonSize)) {
			return true;
		} else {
			return false;
		}
	}
	else if (mapBox.Inside(x, y)) {
		return true;
	}
	else if (showButtons && buttonBox.Inside(x, y)) {
		return true;
	}
	return false;
}


std::string CMiniMap::GetTooltip(int x, int y)
{
	if (minimized) {
		return "Unminimize map";
	}

	if (buttonBox.Inside(x, y)) {
		if (resizeBox.Inside(x, y)) {
			return "Resize map\n(SHIFT to maintain aspect ratio)";
		}
		if (moveBox.Inside(x, y)) {
			return "Move map";
		}
		if (maximizeBox.Inside(x, y)) {
			if (!maximized) {
				return "Maximize map\n(SHIFT to maintain aspect ratio)";
			} else {
				return "Unmaximize map";
			}
		}
		if (minimizeBox.Inside(x, y)) {
			return "Minimize map";
		}
	}

	const string buildTip = guihandler->GetBuildTooltip();
	if (!buildTip.empty()) {
		return buildTip;
	}

	const CUnit* unit = GetSelectUnit(GetMapPosition(x, y));
	if (unit) {
		return CTooltipConsole::MakeUnitString(unit);
	}

	const string selTip = selectedUnits.GetTooltip();
	if (selTip != "") {
		return selTip;
	}

	const float3 pos(float(x-xpos)/width*gs->mapx*SQUARE_SIZE, 500,
	                 float(y-(gu->viewSizeY-ypos-height))/height*gs->mapx*SQUARE_SIZE);
	return CTooltipConsole::MakeGroundString(pos);
}


void CMiniMap::AddNotification(float3 pos, float3 color, float alpha)
{
	Notification n;
	n.pos = pos;
	n.color[0] = color.x;
	n.color[1] = color.y;
	n.color[2] = color.z;
	n.color[3] = alpha;
	n.creationTime = gu->gameTime;

	notes.push_back(n);
}


/******************************************************************************/

inline void DrawInMap2D(float x, float z)
{
	glVertex2f(x, z);
}


void CMiniMap::DrawCircle(const float3& pos, float radius)
{
	glPushMatrix();
	glTranslatef(pos.x, pos.y, pos.z);
	glScalef(radius, 1.0f, radius);

	const float xPixels = radius * float(width) / float(gs->mapx * SQUARE_SIZE);
	const float yPixels = radius * float(height) / float(gs->mapy * SQUARE_SIZE);
	const int lod = (int)(0.25 * log2(1.0f + (xPixels * yPixels)));
	const int lodClamp = max(0, min(circleListsCount - 1, lod));
	glCallList(circleLists + lodClamp);

	glPopMatrix();
}


void CMiniMap::DrawSurfaceCircle(const float3& pos, float radius, unsigned int)
{
	minimap->DrawCircle(pos, radius);
}


void CMiniMap::Draw()
{
	if (!slaveDrawMode) {
		DrawForReal();
	}
}


void CMiniMap::DrawForReal()
{
	SCOPED_TIMER("Draw minimap");

	glEnable(GL_BLEND);
	glDepthFunc(GL_LEQUAL);
	setSurfaceCircleFunc(DrawSurfaceCircle);
	cursorIcons.Enable(false);

	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	if (minimized) {
		if (!slaveDrawMode) {
			DrawMinimizedButton();
		}
		cursorIcons.Enable(true);
		setSurfaceCircleFunc(NULL);
		return;
	}

	glViewport(xpos, ypos, width, height);
	glLoadIdentity();
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(0.0, 1.0, 0.0, 1.0, -1.0e6, +1.0e6);
	glMatrixMode(GL_MODELVIEW);

	glColor4f(0.6f, 0.6f, 0.6f, 1.0f);

	// draw the map
	glDisable(GL_BLEND);
	readmap->DrawMinimap();
	glEnable(GL_BLEND);

	// move some of the transform to the GPU
	glTranslatef(0.0f, +1.0f, 0.0f);
	glScalef(+1.0f / (gs->mapx * SQUARE_SIZE), -1.0f / (gs->mapy * SQUARE_SIZE), 1.0);

	// draw the units
	list<CUnit*>::iterator ui;
	for(ui=uh->activeUnits.begin();ui!=uh->activeUnits.end();ui++){
		DrawUnit(*ui);
	}

	// highlight the selected unit
	CUnit* unit = GetSelectUnit(GetMapPosition(mouse->lastx, mouse->lasty));
	if (unit != NULL) {
		DrawUnitHighlight(unit);
	}

	glDisable(GL_TEXTURE_2D);

	left.clear();

	// add restraints for camera sides
	GetFrustumSide(cam2->bottom);
	GetFrustumSide(cam2->top);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?