예제 #1
0
파일: viewport.c 프로젝트: 166MMX/OpenDUNE
/**
 * Handles the Click events for the Viewport widget.
 *
 * @param w The widget.
 */
bool GUI_Widget_Viewport_Click(Widget *w)
{
	uint16 direction;
	uint16 x, y;
	uint16 spriteID;
	uint16 packed;
	bool click, drag;

	spriteID = g_cursorSpriteID;
	switch (w->index) {
		default: break;
		case 39: spriteID = 1; break;
		case 40: spriteID = 2; break;
		case 41: spriteID = 4; break;
		case 42: spriteID = 3; break;
		case 43: spriteID = g_cursorDefaultSpriteID; break;
		case 44: spriteID = g_cursorDefaultSpriteID; break;
		case 45: spriteID = 0; break;
	}

	if (spriteID != g_cursorSpriteID) {
		/* HotSpots for different cursor types. */
		static const XYPosition cursorHotSpots[6] = {{0, 0}, {5, 0}, {8, 5}, {5, 8}, {0, 5}, {8, 8}};

		s_tickCursor = g_timerGame;

		Sprites_SetMouseSprite(cursorHotSpots[spriteID].x, cursorHotSpots[spriteID].y, g_sprites[spriteID]);

		g_cursorSpriteID = spriteID;
	}

	if (w->index == 45) return true;

	click = false;
	drag = false;

	if ((w->state.buttonState & 0x11) != 0) {
		click = true;
		g_var_37B8 = false;
	} else if ((w->state.buttonState & 0x22) != 0 && !g_var_37B8) {
		drag = true;
	}

	/* ENHANCEMENT -- Dune2 depends on slow CPUs to limit the rate mouse clicks are handled. */
	if (g_dune2_enhanced && (click || drag)) {
		if (s_tickClick + 2 >= g_timerGame) return true;
		s_tickClick = g_timerGame;
	}

	direction = 0xFFFF;
	switch (w->index) {
		default: break;
		case 39: direction = 0; break;
		case 40: direction = 2; break;
		case 41: direction = 6; break;
		case 42: direction = 4; break;
	}

	if (direction != 0xFFFF) {
		/* Always scroll if we have a click or a drag */
		if (!click && !drag) {
			/* Wait for either one of the timers */
			if (s_tickMapScroll + 10 >= g_timerGame || s_tickCursor + 20 >= g_timerGame) return true;
			/* Don't scroll if we have a structure/unit selected and don't want to autoscroll */
			if (g_gameConfig.autoScroll == 0 && (g_selectionType == SELECTIONTYPE_STRUCTURE || g_selectionType == SELECTIONTYPE_UNIT)) return true;
		}

		s_tickMapScroll = g_timerGame;

		Map_MoveDirection(direction);
		return true;
	}

	if (click) {
		x = g_mouseClickX;
		y = g_mouseClickY;
	} else {
		x = g_mouseX;
		y = g_mouseY;
	}

	if (w->index == 43) {
		x =  x / 16 + Tile_GetPackedX(g_minimapPosition);
		y = (y - 40) / 16 + Tile_GetPackedY(g_minimapPosition);
	} else if (w->index == 44) {
		uint16 mapScale;
		const MapInfo *mapInfo;

		mapScale = g_scenario.mapScale;
		mapInfo = &g_mapInfos[mapScale];

		x = min((max(x, 256) - 256) / (mapScale + 1), mapInfo->sizeX - 1) + mapInfo->minX;
		y = min((max(y, 136) - 136) / (mapScale + 1), mapInfo->sizeY - 1) + mapInfo->minY;
	}

	packed = Tile_PackXY(x, y);

	if (click && g_selectionType == SELECTIONTYPE_TARGET) {
		Unit *u;
		ActionType action;
		uint16 encoded;

		GUI_DisplayText(NULL, -1);

		if (g_unitHouseMissile != NULL) {
			Unit_LaunchHouseMissile(packed);
			return true;
		}

		u = g_unitActive;

		action = g_activeAction;

		Object_Script_Variable4_Clear(&u->o);
		u->targetAttack   = 0;
		u->targetMove     = 0;
		u->route[0] = 0xFF;

		if (action != ACTION_MOVE && action != ACTION_HARVEST) {
			encoded = Tools_Index_Encode(Unit_FindTargetAround(packed), IT_TILE);
		} else {
			encoded = Tools_Index_Encode(packed, IT_TILE);
		}

		Unit_SetAction(u, action);

		if (action == ACTION_MOVE) {
			Unit_SetDestination(u, encoded);
		} else if (action == ACTION_HARVEST) {
			u->targetMove = encoded;
		} else {
			Unit *target;

			Unit_SetTarget(u, encoded);
			target = Tools_Index_GetUnit(u->targetAttack);
			if (target != NULL) target->blinkCounter = 8;
		}

		if (g_enableVoices == 0) {
			Driver_Sound_Play(36, 0xFF);
		} else if (g_table_unitInfo[u->o.type].movementType == MOVEMENT_FOOT) {
			Sound_StartSound(g_table_actionInfo[action].soundID);
		} else {
			Sound_StartSound(((Tools_Random_256() & 0x1) == 0) ? 20 : 17);
		}

		g_unitActive   = NULL;
		g_activeAction = 0xFFFF;

		GUI_ChangeSelectionType(SELECTIONTYPE_UNIT);
		return true;
	}

	if (click && g_selectionType == SELECTIONTYPE_PLACE) {
		const StructureInfo *si;
		Structure *s;
		House *h;

		s = g_structureActive;
		si = &g_table_structureInfo[g_structureActiveType];
		h = g_playerHouse;

		if (Structure_Place(s, g_selectionPosition)) {
			Voice_Play(20);

			if (s->o.type == STRUCTURE_PALACE) House_Get_ByIndex(s->o.houseID)->palacePosition = s->o.position;

			if (g_structureActiveType == STRUCTURE_REFINERY && g_validateStrictIfZero == 0) {
				Unit *u;

				g_validateStrictIfZero++;
				u = Unit_CreateWrapper(g_playerHouseID, UNIT_HARVESTER, Tools_Index_Encode(s->o.index, IT_STRUCTURE));
				g_validateStrictIfZero--;

				if (u == NULL) {
					h->harvestersIncoming++;
				} else {
					u->originEncoded = Tools_Index_Encode(s->o.index, IT_STRUCTURE);
				}
			}

			GUI_ChangeSelectionType(SELECTIONTYPE_STRUCTURE);

			s = Structure_Get_ByPackedTile(g_structureActivePosition);
			if (s != NULL) {
				if ((Structure_GetBuildable(s) & (1 << s->objectType)) == 0) Structure_BuildObject(s, 0xFFFE);
			}

			g_structureActiveType = 0xFFFF;
			g_structureActive     = NULL;
			g_selectionState      = 0; /* Invalid. */

			GUI_DisplayHint(si->o.hintStringID, si->o.spriteID);

			House_UpdateRadarState(h);

			if (h->powerProduction < h->powerUsage) {
				if ((h->structuresBuilt & (1 << STRUCTURE_OUTPOST)) != 0) {
					GUI_DisplayText(String_Get_ByIndex(STR_NOT_ENOUGH_POWER_FOR_RADAR_BUILD_WINDTRAPS), 3);
				}
			}
			return true;
		}

		Voice_Play(47);

		if (g_structureActiveType == STRUCTURE_SLAB_1x1 || g_structureActiveType == STRUCTURE_SLAB_2x2) {
			GUI_DisplayText(String_Get_ByIndex(STR_CAN_NOT_PLACE_FOUNDATION_HERE), 2);
		} else {
			GUI_DisplayHint(STR_STRUCTURES_MUST_BE_PLACED_ON_CLEAR_ROCK_OR_CONCRETE_AND_ADJACENT_TO_ANOTHER_FRIENDLY_STRUCTURE, 0xFFFF);
			GUI_DisplayText(String_Get_ByIndex(STR_CAN_NOT_PLACE_S_HERE), 2, String_Get_ByIndex(si->o.stringID_abbrev));
		}
		return true;
	}

	if (click && w->index == 43) {
		uint16 position;

		if (g_debugScenario) {
			position = packed;
		} else {
			position = Unit_FindTargetAround(packed);
		}

		if (g_map[position].overlaySpriteID != g_veiledSpriteID || g_debugScenario) {
			if (Object_GetByPackedTile(position) != NULL || g_debugScenario) {
				Map_SetSelection(position);
				Unit_DisplayStatusText(g_unitSelected);
			}
		}

		if ((w->state.buttonState & 0x10) != 0) Map_SetViewportPosition(packed);

		return true;
	}

	if ((click || drag) && w->index == 44) {
		Map_SetViewportPosition(packed);
		return true;
	}

	if (g_selectionType == SELECTIONTYPE_TARGET) {
		Map_SetSelection(Unit_FindTargetAround(packed));
	} else if (g_selectionType == SELECTIONTYPE_PLACE) {
		Map_SetSelection(packed);
	}

	return true;
}
예제 #2
0
파일: opendune.c 프로젝트: 166MMX/OpenDUNE
static void InGame_Numpad_Move(uint16 key)
{
	if (key == 0) return;

	switch (key) {
		case 0x0010: /* TAB */
			Map_SelectNext(true);
			return;

		case 0x0110: /* SHIFT TAB */
			Map_SelectNext(false);
			return;

		case 0x005C: /* NUMPAD 4 / ARROW LEFT */
		case 0x045C:
		case 0x055C:
			Map_MoveDirection(6);
			return;

		case 0x0066: /* NUMPAD 6 / ARROW RIGHT */
		case 0x0466:
		case 0x0566:
			Map_MoveDirection(2);
			return;

		case 0x0060: /* NUMPAD 8 / ARROW UP */
		case 0x0460:
		case 0x0560:
			Map_MoveDirection(0);
			return;

		case 0x0062: /* NUMPAD 2 / ARROW DOWN */
		case 0x0462:
		case 0x0562:
			Map_MoveDirection(4);
			return;

		case 0x005B: /* NUMPAD 7 / HOME */
		case 0x045B:
		case 0x055B:
			Map_MoveDirection(7);
			return;

		case 0x005D: /* NUMPAD 1 / END */
		case 0x045D:
		case 0x055D:
			Map_MoveDirection(5);
			return;

		case 0x0065: /* NUMPAD 9 / PAGE UP */
		case 0x0465:
		case 0x0565:
			Map_MoveDirection(1);
			return;

		case 0x0067: /* NUMPAD 3 / PAGE DOWN */
		case 0x0467:
		case 0x0567:
			Map_MoveDirection(3);
			return;

		default: return;
	}
}
예제 #3
0
/* Process input not caught by widgets, including keypad scrolling,
 * squad selection, and changing zoom levels.  Also handles screen
 * shake logic.
 */
static void GameLoop_ProcessUnhandledInput(uint16 key)
{
	const struct
	{
		Scancode code;
		int dx, dy;
	} keypad[8] = {
		{SCANCODE_KEYPAD_1, -1, 1},
		{SCANCODE_KEYPAD_2, 0, 1},
		{SCANCODE_KEYPAD_3, 1, 1},
		{SCANCODE_KEYPAD_4, -1, 0},
		{SCANCODE_KEYPAD_6, 1, 0},
		{SCANCODE_KEYPAD_7, -1, -1},
		{SCANCODE_KEYPAD_8, 0, -1},
		{SCANCODE_KEYPAD_9, 1, -1}
	};

	int dx = 0, dy = 0;

	for (unsigned int i = 0; i < lengthof(keypad); i++)
	{
		if ((key == keypad[i].code) ||
			(key == 0 && Input_Test(keypad[i].code)))
		{
			dx += keypad[i].dx;
			dy += keypad[i].dy;
		}
	}

	if (dx != 0 || dy != 0)
	{
		dx = g_gameConfig.scrollSpeed * clamp(-1, dx, 1);
		dy = g_gameConfig.scrollSpeed * clamp(-1, dy, 1);
	}

	if ((fabsf(g_viewport_desiredDX) >= 4.0f) || (fabsf(g_viewport_desiredDY) >= 4.0f))
	{
		dx += 0.25 * g_viewport_desiredDX;
		dy += 0.25 * g_viewport_desiredDY;
		if (fabsf(g_viewport_desiredDX) >= 4.0f)
			g_viewport_desiredDX *= 0.75;
		if (fabsf(g_viewport_desiredDY) >= 4.0f)
			g_viewport_desiredDY *= 0.75;
	}

	if (dx != 0 || dy != 0)
	{
		Map_MoveDirection(dx, dy);
	}

	switch (key)
	{
	case SCANCODE_1:
	case SCANCODE_2:
	case SCANCODE_3:
	case SCANCODE_4:
	case SCANCODE_5:
	case SCANCODE_6:
	case SCANCODE_7:
	case SCANCODE_8:
	case SCANCODE_9:
	case SCANCODE_0:
		Viewport_Hotkey((SquadID)(key - SCANCODE_1 + SQUADID_1));
		break;

	case SCANCODE_H:
		Viewport_Homekey();
		break;

	case SCANCODE_F5:
		Audio_DisplayMusicName();
		break;

	case SCANCODE_F6:
	case SCANCODE_F7:
		{
			const bool increase = (key == SCANCODE_F7);
			const bool adjust_current_track_only = Input_Test(SCANCODE_LSHIFT);

			Audio_AdjustMusicVolume(increase ? 0.05f : -0.05f, adjust_current_track_only);
			Audio_DisplayMusicName();
		}
		break;

	case SCANCODE_OPENBRACE:
	case SCANCODE_CLOSEBRACE:
		{
			ScreenDivID divID = (key == SCANCODE_OPENBRACE) ? SCREENDIV_MENUBAR : SCREENDIV_SIDEBAR;
			ScreenDiv* viewport = &g_screenDiv[SCREENDIV_VIEWPORT];
			ScreenDiv* div = &g_screenDiv[divID];
			const int oldh = viewport->height;

			div->scalex = (div->scalex >= 1.5f) ? 1.0f : 2.0f;
			div->scaley = div->scalex;
			A5_InitTransform(false);
			GameLoop_TweakWidgetDimensions();
			g_factoryWindowTotal = -1;
			Map_MoveDirection(0, oldh - viewport->height);
		}
		return;

	case 0x80 | MOUSE_ZAXIS:
		if (g_mouseDZ == 0)
			break;

		if (g_gameConfig.holdControlToZoom)
		{
			if (!Input_Test(SCANCODE_LCTRL))
			{
				Widget* w = GUI_Widget_Get_ByIndex(g_widgetLinkedListHead, 5);

				if ((w != NULL) && !w->flags.invisible)
					GUI_Widget_SpriteTextButton_Click(w);

				break;
			}
		}
		else
		{
			const WidgetProperties* w = &g_widgetProperties[WINDOWID_ACTIONPANEL_FRAME];

			if (Mouse_InRegion_Div(SCREENDIV_SIDEBAR, w->xBase, w->yBase, w->xBase + w->width - 1, w->yBase + w->height - 1))
				break;
		}
		/* Fall though. */
	case SCANCODE_MINUS:
	case SCANCODE_EQUALS:
	case SCANCODE_KEYPAD_MINUS:
	case SCANCODE_KEYPAD_PLUS:
		{
			const float scaling_factor[] = {1.0f, 1.5f, 2.0f, 3.0f};
			ScreenDiv* viewport = &g_screenDiv[SCREENDIV_VIEWPORT];

			int curr;
			for (curr = 0; curr < (int)lengthof(scaling_factor); curr++)
			{
				if (viewport->scalex <= scaling_factor[curr])
					break;
			}

			const int tilex = Tile_GetPackedX(g_viewportPosition);
			const int tiley = Tile_GetPackedY(g_viewportPosition);
			int viewport_cx = g_viewport_scrollOffsetX + viewport->width / 2;
			int viewport_cy = g_viewport_scrollOffsetY + viewport->height / 2;
			int new_scale;

			/* For mouse wheel zooming in, zoom towards the cursor. */
			if ((key == (0x80 | MOUSE_ZAXIS)) && (g_mouseDZ > 0))
			{
				const ScreenDiv* div = &g_screenDiv[SCREENDIV_VIEWPORT];

				if (Mouse_InRegion_Div(SCREENDIV_VIEWPORT, 0, 0, div->width, div->height))
				{
					int mousex, mousey;

					new_scale = curr + 1;

					Mouse_TransformToDiv(SCREENDIV_VIEWPORT, &mousex, &mousey);
					viewport_cx = (0.50 * viewport_cx) + (0.50 * mousex);
					viewport_cy = (0.50 * viewport_cy) + (0.50 * mousey);
				}
				else
				{
					new_scale = curr + 1;
				}
			}
			else
			{
				if (key == SCANCODE_EQUALS || key == SCANCODE_KEYPAD_PLUS)
				{
					new_scale = curr + 1;
				}
				else
				{
					new_scale = curr - 1;
				}
			}

			new_scale = clamp(0, new_scale, (int)lengthof(scaling_factor) - 1);
			viewport_cx += TILE_SIZE * tilex;
			viewport_cy += TILE_SIZE * tiley;

			if (new_scale != curr)
			{
				viewport->scalex = scaling_factor[new_scale];
				viewport->scaley = scaling_factor[new_scale];
				A5_InitTransform(false);
				GameLoop_TweakWidgetDimensions();
				Map_CentreViewport(viewport_cx, viewport_cy);
				return;
			}
		}
		break;

	default:
		break;
	}

	/* If we did not init the transform, we may still need to do some
	 * translation transforms for screen shakes.
	 */
	if (GFX_ScreenShake_Tick())
		A5_InitTransform(false);
}