Ejemplo n.º 1
0
/**
 * Refine spice in the current structure.
 *
 * Stack: *none*
 *
 * @param script The script engine to operate on.
 * @return 0 if there is no spice to refine, otherwise 1.
 */
uint16 Script_Structure_RefineSpice(ScriptEngine *script)
{
	const StructureInfo *si;
	Structure *s;
	Unit *u;
	House *h;
	uint16 harvesterStep, creditsStep;

	VARIABLE_NOT_USED(script);

	s = g_scriptCurrentStructure;

	if (s->o.linkedID == 0xFF) {
		Structure_SetState(s, STRUCTURE_STATE_IDLE);
		return 0;
	}

	u = Unit_Get_ByIndex(s->o.linkedID);
	si = &g_table_structureInfo[s->o.type];

	harvesterStep = (s->o.hitpoints * 256 / si->o.hitpoints) * 3 / 256;

	if (u->amount < harvesterStep) harvesterStep = u->amount;
	if (u->amount != 0 && harvesterStep < 1) harvesterStep = 1;
	if (harvesterStep == 0) return 0;

	creditsStep = 7;
	if (u->o.houseID != g_playerHouseID) {
		creditsStep += (Tools_Random_256() % 4) - 1;
	}

	creditsStep *= harvesterStep;

	if (House_AreAllied(g_playerHouseID, s->o.houseID)) {
		g_scenario.harvestedAllied += creditsStep;
		if (g_scenario.harvestedAllied > 65000) g_scenario.harvestedAllied = 65000;
	} else {
		g_scenario.harvestedEnemy += creditsStep;
		if (g_scenario.harvestedEnemy > 65000) g_scenario.harvestedEnemy = 65000;
	}

	h = House_Get_ByIndex(s->o.houseID);
	h->credits += creditsStep;
	u->amount -= harvesterStep;

	if (u->amount == 0) u->o.flags.s.inTransport = false;
	s->o.script.delay = 6;
	return 1;
}
Ejemplo n.º 2
0
/**
 * Find a Unit which is within range and not an ally.
 *
 * Stack: 1 - Range to find a target in (amount of tiles multiplied with 256).
 *
 * @param script The script engine to operate on.
 * @return The Unit Index of the closest unit within range and not friendly,
 *   or 0 if none exists.
 */
uint16 Script_Structure_FindTargetUnit(ScriptEngine *script)
{
	PoolFindStruct find;
	Structure *s;
	Unit *u;
	uint32 distanceCurrent;
	uint32 targetRange;

	s = g_scriptCurrentStructure;
	targetRange = STACK_PEEK(1);
	distanceCurrent = 32000;
	u = NULL;

	find.houseID = HOUSE_INVALID;
	find.index   = 0xFFFF;
	find.type    = 0xFFFF;

	while (true) {
		uint16 distance;
		Unit *uf;

		uf = Unit_Find(&find);
		if (uf == NULL) break;

		if (House_AreAllied(s->o.houseID, uf->o.houseID)) continue;

		if (uf->o.type != UNIT_ORNITHOPTER) {
			if ((uf->o.seenByHouses & (1 << s->o.houseID)) == 0) continue;
		}

		distance = Tile_GetDistance(uf->o.position, s->o.position);
		if (distance >= distanceCurrent) continue;

		if (uf->o.type == UNIT_ORNITHOPTER) {
			if (distance >= targetRange * 3) continue;
		} else {
			if (distance >= targetRange) continue;
		}

		/* ENHANCEMENT -- The original code swapped the assignment, making it do nothing, Now it finds the closest unit to shoot at, what seems to be the intention */
		if (g_dune2_enhanced) distanceCurrent = distance;
		u = uf;
	}

	if (u == NULL) return IT_NONE;
	return Tools_Index_Encode(u->o.index, IT_UNIT);
}
Ejemplo n.º 3
0
static void Skirmish_FindClosestStructures(HouseType houseID, uint16 packed, uint16* dist_ally, uint16* dist_enemy)
{
	PoolFindStruct find;
	Structure* s;

	find.houseID = HOUSE_INVALID;
	find.type = 0xFFFF;
	find.index = STRUCTURE_INDEX_INVALID;

	*dist_ally = 0xFFFF;
	*dist_enemy = 0xFFFF;
	while ((s = Structure_Find(&find)) != NULL)
	{
		if (s->o.type == STRUCTURE_SLAB_1x1 || s->o.type == STRUCTURE_SLAB_2x2 || s->o.type == STRUCTURE_WALL)
			continue;

		const uint16 dist = Tile_GetDistancePacked(Tile_PackTile(s->o.position), packed);
		if (House_AreAllied(houseID, s->o.houseID))
			*dist_ally = min(dist, *dist_ally);
		else
			*dist_enemy = min(dist, *dist_enemy);
	}
}
Ejemplo n.º 4
0
static bool Skirmish_GenUnitsHuman(HouseType houseID, SkirmishData* sd)
{
	const int delta[7] = {
		0, -4, 4,
		-MAP_SIZE_MAX * 3 - 2, -MAP_SIZE_MAX * 3 + 2,
		MAP_SIZE_MAX * 3 - 2, MAP_SIZE_MAX * 3 + 2,
	};

	const MapInfo* mi = &g_mapInfos[0];

	/* Pick a tile that is not too close to the edge, and not too
	 * close to the enemy.
	 */
	int r;
	for (int attempts = 0; attempts < 100; attempts++)
	{
		const int island = Skirmish_PickRandomIsland(sd);
		if (island < 0)
			return false;

		r = Tools_RandomLCG_Range(sd->island[island].start, sd->island[island].end - 1);
		if (!(mi->minX + 4 <= sd->buildable[r].x && sd->buildable[r].x < mi->minX + mi->sizeX - 4))
			continue;

		if (!(mi->minY + 3 <= sd->buildable[r].y && sd->buildable[r].y < mi->minY + mi->sizeY - 3))
			continue;

		PoolFindStruct find;
		find.houseID = HOUSE_INVALID;
		find.type = 0xFFFF;
		find.index = STRUCTURE_INDEX_INVALID;

		Structure* s = Structure_Find(&find);
		for (; s != NULL; s = Structure_Find(&find))
		{
			if (s->o.type == STRUCTURE_SLAB_1x1 || s->o.type == STRUCTURE_SLAB_2x2 || s->o.type == STRUCTURE_WALL)
				continue;

			if (House_AreAllied(g_playerHouseID, s->o.houseID))
				continue;

			const uint16 dist = Tile_GetDistancePacked(Tile_PackTile(s->o.position), sd->buildable[r].packed);
			if (dist < 24)
				break;
		}

		if (s == NULL)
		{
			break;
		}
		else
		{
			r = -1;
		}
	}

	if (r < 0)
		return false;

	bool mcvPlaced = false;

	for (int i = 0; i < 7; i++)
	{
		const uint16 packed = sd->buildable[r].packed + delta[i];
		const tile32 position = Tile_UnpackTile(packed);

		UnitType type;
		
		if (!mcvPlaced)
			type = UNIT_MCV;
		else if (i >= 0 && i < 3)
			type = UNIT_SIEGE_TANK;
		else if (i >= 3 && i < 4)
			type = House_GetIXVehicle(houseID);
		else if (i >= 4 && i < 5)
			type = House_GetMediumVehicle(houseID);
		else if (i >= 5 && i < 6)
			type = UNIT_QUAD;
		else if (i >= 6)
			type = House_GetInfantrySquad(houseID);
		
		const LandscapeType lst = (const LandscapeType)Map_GetLandscapeType(packed);

		/* If there's a structure or a bloom here, tough luck. */
		if (lst == LST_STRUCTURE || lst == LST_BLOOM_FIELD)
			continue;

		/* If there's a mountain here, build infantry instead. */
		if (lst == LST_ENTIRELY_MOUNTAIN || lst == LST_PARTIAL_MOUNTAIN)
			type = House_GetInfantrySquad(houseID);

		Scenario_Create_Unit(houseID, type, 256, position, 127, (UnitActionType)g_table_unitInfo[type].o.actionsPlayer[3]);

		if (type == UNIT_MCV)
			mcvPlaced = true;
	}

	return true;
}
Ejemplo n.º 5
0
static bool Skirmish_GenStructuresAI(HouseType houseID, SkirmishData* sd)
{
	uint16 tech_level = 0;
	uint16 structure = 0;
	int structure_count = 0;
	int structure_threshold = 100;

	int cpu_count = 0;
	for (HouseType h = HOUSE_HARKONNEN; h < HOUSE_MAX; h++)
	{
		if (g_skirmish.brain[h] == BRAIN_CPU_ENEMY || g_skirmish.brain[h] == BRAIN_CPU_ALLY)
			cpu_count++;
	}
	assert(cpu_count != 0);

	const int max_structure_count = 60 / cpu_count;

	/* First pass finds out what to build. */
	tech_level = 0;
	structure = 0;
	structure_count = 0;
	for (structure = 0; (structure < lengthof(buildorder)) && (tech_level <= g_techLevel); structure++)
	{
		if (buildorder[structure].type == STRUCTURE_INVALID)
			tech_level++;
		else if ((buildorder[structure].availableHouse & (1 << houseID)) != 0)
			structure_count++;
	}

	if (structure_count > max_structure_count)
	{
		structure_count = max_structure_count;

		SkirmishBuildOrder* bo = (SkirmishBuildOrder*)malloc(structure * sizeof(SkirmishBuildOrder));
		assert(bo != NULL);

		memcpy(bo, buildorder, structure * sizeof(SkirmishBuildOrder));
		qsort(bo, structure, sizeof(SkirmishBuildOrder), Skirmish_BuildOrder_Sorter);
		structure_threshold = bo[structure_count].priority;

		free(bo);
	}

	/* Second pass builds structures below the threshold priority. */
	tech_level = 0;
	structure = 0;
	for (int attempts = 0; attempts < 100; attempts++)
	{
		int island = Skirmish_PickRandomIsland(sd);
		int range = 8;
		if (island < 0)
			return false;

		/* Re-flood-fill the island, using a new starting point. */
		{
			const int r = Tools_RandomLCG_Range(sd->island[island].start, sd->island[island].end - 1);

			uint16 dist_ally, dist_enemy;
			Skirmish_FindClosestStructures(houseID, sd->buildable[r].packed, &dist_ally, &dist_enemy);

			if ((dist_ally > 16 && dist_ally != 0xFFFF) ||
				(dist_enemy < 24))
				continue;

			const int area = Skirmish_FindBuildableArea(island, sd->buildable[r].x, sd->buildable[r].y,
			                                            sd, sd->buildable + sd->island[island].start);
			assert(area == sd->island[island].end - sd->island[island].start);
			UNUSED(area);

			for (int i = sd->island[island].start; i < sd->island[island].end; i++)
				sd->islandID[sd->buildable[i].packed] = island;
		}

		/* Use no-cheat-mode to verify land is buildable. */
		g_validateStrictIfZero--;
		assert(g_validateStrictIfZero == 0);

		/* Place structures. */
		while (structure_count > 0)
		{
			assert(structure < lengthof(buildorder));

			if (buildorder[structure].type == STRUCTURE_INVALID)
			{
				tech_level++;
				structure++;
				continue;
			}

			if (buildorder[structure].priority >= structure_threshold)
			{
				structure++;
				continue;
			}

			const StructureType type = buildorder[structure].type;
			const StructureInfo* si = &g_table_structureInfo[type];
			const int r = Tools_RandomLCG_Range(0, range - 1);
			const uint16 packed = sd->buildable[sd->island[island].start + r].packed;

			if (Structure_IsValidBuildLandscape(packed, type) != 0)
			{
				Structure* s = Structure_Create(STRUCTURE_INDEX_INVALID, type, houseID, packed);
				assert(s != NULL);

				s->o.hitpoints = si->o.hitpoints;
				s->o.flags.s.degrades = false;
				s->state = STRUCTURE_STATE_IDLE;

				if (House_AreAllied(g_playerHouseID, houseID))
					s->o.seenByHouses = 0xFF;

				if (s->o.type == STRUCTURE_PALACE)
					s->countDown = g_table_houseInfo[houseID].specialCountDown;

				range = min(range + 4, sd->island[island].end - sd->island[island].start);
				structure++;
				structure_count--;
			}
			else
			{
				range++;

				if (range > sd->island[island].end - sd->island[island].start)
					break;
			}
		}

		/* Connect structures on this island with concrete slabs. */
		for (range--; range > 0; range--)
		{
			const int self = sd->island[island].start + range;
			uint16 packed = sd->buildable[self].packed;

			const LandscapeType lst = (const LandscapeType)Map_GetLandscapeType(packed);
			if (lst != LST_STRUCTURE && lst != LST_CONCRETE_SLAB)
				continue;

			const int parent = sd->island[island].start + sd->buildable[self].parent;
			packed = sd->buildable[parent].packed;
			if (Structure_IsValidBuildLandscape(packed, STRUCTURE_SLAB_1x1) == 0)
				continue;

			g_validateStrictIfZero++;
			Structure_Create(STRUCTURE_INDEX_INVALID, STRUCTURE_SLAB_1x1, houseID, packed);
			g_validateStrictIfZero--;
		}

		/* Finished building on this island.  Create sub-islands from
		 * remaining buildable tiles.
		 */
		g_validateStrictIfZero++;
		Skirmish_DivideIsland(houseID, island, sd);

		if (structure_count <= 0)
			return true;
	}

	return false;
}
Ejemplo n.º 6
0
/**
 * Check if a level is finished, based on the values in WinFlags.
 *
 * @return True if and only if the level has come to an end.
 */
static bool GameLoop_IsLevelFinished()
{
	bool finish = false;

	if (s_debugForceWin)
		return true;

	/* You have to play at least 7200 ticks before you can win the game */
	if (g_timerGame - g_tickScenarioStart < 7200)
		return false;

	/* Check for structure counts hitting zero */
	if ((g_scenario.winFlags & 0x3) != 0)
	{
		PoolFindStruct find;
		uint16 countStructureEnemy = 0;
		uint16 countStructureFriendly = 0;

		find.houseID = HOUSE_INVALID;
		find.type = 0xFFFF;
		find.index = 0xFFFF;

		/* Calculate how many structures are left on the map */
		while (true)
		{
			Structure* s;

			s = Structure_Find(&find);
			if (s == NULL)
				break;

			if (s->o.type == STRUCTURE_SLAB_1x1 || s->o.type == STRUCTURE_SLAB_2x2 || s->o.type == STRUCTURE_WALL)
				continue;
			if (s->o.type == STRUCTURE_TURRET)
				continue;
			if (s->o.type == STRUCTURE_ROCKET_TURRET)
				continue;

			if (House_AreAllied(s->o.houseID, g_playerHouseID))
				countStructureFriendly++;
			else
				countStructureEnemy++;
		}

		if ((g_scenario.winFlags & 0x1) != 0 && countStructureEnemy == 0)
			finish = true;
		if ((g_scenario.winFlags & 0x2) != 0 && countStructureFriendly == 0)
			finish = true;
	}

	/* Check for reaching spice quota */
	if ((g_scenario.winFlags & 0x4) != 0 && g_playerCredits != 0xFFFF)
	{
		if (g_playerCredits >= g_playerHouse->creditsQuota)
			finish = true;
	}

	/* Check for reaching timeout */
	if ((g_scenario.winFlags & 0x8) != 0)
	{
		/* XXX -- This code was with '<' instead of '>=', which makes
		 *  no sense. As it is unused, who knows what the intentions
		 *  were. This at least makes it sensible. */
		if (g_timerGame - g_tickScenarioStart >= g_scenario.timeOut)
		{
			finish = true;
		}
	}

	return finish;
}
Ejemplo n.º 7
0
/**
 * Check if a level is won, based on the values in LoseFlags.
 *
 * @return True if and only if the level has been won by the human.
 */
static bool GameLoop_IsLevelWon()
{
	bool win = false;

	if (s_debugForceWin)
		return true;

	/* Check for structure counts hitting zero */
	if ((g_scenario.loseFlags & 0x3) != 0)
	{
		PoolFindStruct find;
		uint16 countStructureEnemy = 0;
		uint16 countStructureFriendly = 0;

		find.houseID = HOUSE_INVALID;
		find.type = 0xFFFF;
		find.index = 0xFFFF;

		/* Calculate how many structures are left on the map */
		while (true)
		{
			Structure* s;

			s = Structure_Find(&find);
			if (s == NULL)
				break;

			if (s->o.type == STRUCTURE_SLAB_1x1 || s->o.type == STRUCTURE_SLAB_2x2 || s->o.type == STRUCTURE_WALL)
				continue;
			if (s->o.type == STRUCTURE_TURRET)
				continue;
			if (s->o.type == STRUCTURE_ROCKET_TURRET)
				continue;

			if (House_AreAllied(s->o.houseID, g_playerHouseID))
				countStructureFriendly++;
			else
				countStructureEnemy++;
		}

		win = true;
		if ((g_scenario.loseFlags & 0x1) != 0)
			win = win && (countStructureEnemy == 0);

		if ((g_scenario.loseFlags & 0x2) != 0)
			win = win && (countStructureFriendly != 0);
	}

	/* Check for reaching spice quota */
	if (!win && (g_scenario.loseFlags & 0x4) != 0 && g_playerCredits != 0xFFFF)
		win = (g_playerCredits >= g_playerHouse->creditsQuota);

	/* Check for reaching timeout */
	if (!win && (g_scenario.loseFlags & 0x8) != 0)
	{
		/* ENHANCEMENT -- Same deal as for winFlags above.
		 * This way we can make win-after-timeout (survival) and
		 * lose-after-timeout (countdown) missions.
		 *
		 * survival: winFlags = 11, loseFlags = 9.
		 * lose:     winFlags = 11, loseFlags = 1.
		 */
		win = (g_timerGame - g_tickScenarioStart >= g_scenario.timeOut);
	}

	return win;
}