예제 #1
0
파일: structure.c 프로젝트: 166MMX/OpenDUNE
/**
 * Allocate a Structure.
 *
 * @param index The index to use, or STRUCTURE_INDEX_INVALID to find an unused index.
 * @param typeID The type of the new Structure.
 * @return The Structure allocated, or NULL on failure.
 */
Structure *Structure_Allocate(uint16 index, uint8 type)
{
	Structure *s = NULL;

	switch (type) {
		case STRUCTURE_SLAB_1x1:
			index = STRUCTURE_INDEX_SLAB_1x1;
			s = Structure_Get_ByIndex(index);
			break;

		case STRUCTURE_SLAB_2x2:
			index = STRUCTURE_INDEX_SLAB_2x2;
			s = Structure_Get_ByIndex(index);
			break;

		case STRUCTURE_WALL:
			index = STRUCTURE_INDEX_WALL;
			s = Structure_Get_ByIndex(index);
			break;

		default:
			if (index == STRUCTURE_INDEX_INVALID) {
				/* Find the first unused index */
				for (index = 0; index < STRUCTURE_INDEX_MAX_SOFT; index++) {
					s = Structure_Get_ByIndex(index);
					if (!s->o.flags.s.used) break;
				}
				if (index == STRUCTURE_INDEX_MAX_SOFT) return NULL;
			} else {
				s = Structure_Get_ByIndex(index);
				if (s->o.flags.s.used) return NULL;
			}

			g_structureFindArray[g_structureFindCount++] = s;
			break;
	}
	assert(s != NULL);

	/* Initialize the Structure */
	memset(s, 0, sizeof(Structure));
	s->o.index             = index;
	s->o.type              = type;
	s->o.linkedID          = 0xFF;
	s->o.flags.s.used      = true;
	s->o.flags.s.allocated = true;
	s->o.script.delay = 0;

	return s;
}
예제 #2
0
파일: unit.c 프로젝트: rofl0r/OpenDUNE
/**
 * Check if the given tile is a valid destination. In case of for example
 *  a carry-all it checks if the unit carrying can be placed on destination.
 * In case of structures, it checks if you can walk into it.
 *
 * Stack: 1 - An encoded tile, indicating the destination.
 *
 * @param script The script engine to operate on.
 * @return ??.
 */
uint16 Script_Unit_IsValidDestination(ScriptEngine *script)
{
	Unit *u;
	Unit *u2;
	uint16 encoded;
	uint16 index;

	u = g_scriptCurrentUnit;
	encoded = STACK_PEEK(1);
	index = Tools_Index_Decode(encoded);

	switch (Tools_Index_GetType(encoded)) {
		case IT_TILE:
			if (!Map_IsValidPosition(index)) return 1;
			if (u->o.linkedID == 0xFF) return 1;
			u2 = Unit_Get_ByIndex(u->o.linkedID);
			u2->o.position = Tools_Index_GetTile(encoded);
			if (!Unit_IsTileOccupied(u2)) return 0;
			u2->o.position.tile = 0xFFFFFFFF;
			return 1;

		case IT_STRUCTURE: {
			Structure *s;

			s = Structure_Get_ByIndex(index);
			if (s->o.houseID == Unit_GetHouseID(u)) return 0;
			if (u->o.linkedID == 0xFF) return 1;
			u2 = Unit_Get_ByIndex(u->o.linkedID);
			return Unit_IsValidMovementIntoStructure(u2, s) != 0 ? 1 : 0;
		}

		default: return 1;
	}
}
예제 #3
0
/**
 * @brief   f__167E_0005_0013_AF0C.
 * @details Removed guard for IT_UNIT.
 */
bool Tools_Index_IsValid(uint16 encoded)
{
	if (encoded == 0)
		return false;

	uint16 index = Tools_Index_Decode(encoded);
	switch (Tools_Index_GetType(encoded))
	{
	case IT_UNIT:
		{
			const Unit* u = Unit_Get_ByIndex(index);
			return u->o.flags.s.used && u->o.flags.s.allocated;
		}

	case IT_STRUCTURE:
		{
			const Structure* s = Structure_Get_ByIndex(index);
			return s->o.flags.s.used;
		}

	case IT_TILE:
	case IT_NONE:
	default:
		return true;
	}

	return false;
}
예제 #4
0
파일: structure.c 프로젝트: 166MMX/OpenDUNE
/**
 * Load all Structures from a file.
 * @param fp The file to load from.
 * @param length The length of the data chunk.
 * @return True if and only if all bytes were read successful.
 */
bool Structure_Load(FILE *fp, uint32 length)
{
	while (length > 0) {
		Structure *s;
		Structure sl;

		memset(&sl, 0, sizeof(sl));

		/* Read the next Structure from disk */
		if (!SaveLoad_Load(s_saveStructure, fp, &sl)) return false;

		length -= SaveLoad_GetLength(s_saveStructure);

		sl.o.script.scriptInfo = g_scriptStructure;
		sl.o.script.script = g_scriptStructure->start + (size_t)sl.o.script.script;
		if (sl.upgradeTimeLeft == 0) sl.upgradeTimeLeft = Structure_IsUpgradable(&sl) ? 100 : 0;

		/* Get the Structure from the pool */
		s = Structure_Get_ByIndex(sl.o.index);
		if (s == NULL) return false;

		/* Copy over the data */
		*s = sl;
	}
	if (length != 0) return false;

	Structure_Recount();

	return true;
}
예제 #5
0
파일: structure.c 프로젝트: 166MMX/OpenDUNE
/**
 * Find the first matching Structure based on the PoolFindStruct filter data.
 *
 * @param find A pointer to a PoolFindStruct which contains filter data and
 *   last known tried index. Calling this functions multiple times with the
 *   same 'find' parameter walks over all possible values matching the filter.
 * @return The Structure, or NULL if nothing matches (anymore).
 */
Structure *Structure_Find(PoolFindStruct *find)
{
	if (find->index >= g_structureFindCount + 3 && find->index != 0xFFFF) return NULL;
	find->index++; /* First, we always go to the next index */

	assert(g_structureFindCount <= STRUCTURE_INDEX_MAX_SOFT);
	for (; find->index < g_structureFindCount + 3; find->index++) {
		Structure *s = NULL;

		if (find->index < g_structureFindCount) {
			s = g_structureFindArray[find->index];
		} else {
			/* There are 3 special structures that are never in the Find array */
			assert(find->index - g_structureFindCount < 3);
			switch (find->index - g_structureFindCount) {
				case 0:
					s = Structure_Get_ByIndex(STRUCTURE_INDEX_WALL);
					if (s->o.index != STRUCTURE_INDEX_WALL) continue;
					break;

				case 1:
					s = Structure_Get_ByIndex(STRUCTURE_INDEX_SLAB_2x2);
					if (s->o.index != STRUCTURE_INDEX_SLAB_2x2) continue;
					break;

				case 2:
					s = Structure_Get_ByIndex(STRUCTURE_INDEX_SLAB_1x1);
					if (s->o.index != STRUCTURE_INDEX_SLAB_1x1) continue;
					break;
			}
		}
		if (s == NULL) continue;

		if (s->o.flags.s.isNotOnMap && g_validateStrictIfZero == 0) continue;
		if (find->houseID != HOUSE_INVALID           && find->houseID != s->o.houseID) continue;
		if (find->type    != STRUCTURE_INDEX_INVALID && find->type    != s->o.type)  continue;

		return s;
	}

	return NULL;
}
예제 #6
0
파일: object.cpp 프로젝트: SkrilaxCZ/Dune2
/**
 * Get the object on the given packed tile.
 * @param packed The packed tile to get the object from.
 * @return The object.
 */
Object* Object_GetByPackedTile(uint16 packed)
{
	Tile* t;

	if (Tile_IsOutOfMap(packed))
		return NULL;

	t = &g_map[packed];
	if (t->hasUnit)
		return &Unit_Get_ByIndex(t->index - 1)->o;
	if (t->hasStructure)
		return &Structure_Get_ByIndex(t->index - 1)->o;
	return NULL;
}
예제 #7
0
/**
 * Handles Click event for a sprite/text button.
 *
 * @param w The widget.
 * @return False, always.
 */
bool GUI_Widget_SpriteTextButton_Click(Widget *w)
{
	Structure *s;

	VARIABLE_NOT_USED(w);

	s = Structure_Get_ByPackedTile(g_selectionPosition);

	switch (g_productionStringID) {
		default: break;

		case STR_PLACE_IT:
			if (s->o.type == STRUCTURE_CONSTRUCTION_YARD) {
				Structure *ns;

				ns = Structure_Get_ByIndex(s->o.linkedID);
				g_structureActive = ns;
				g_structureActiveType = s->objectType;
				g_selectionState = Structure_IsValidBuildLocation(g_selectionRectanglePosition, g_structureActiveType);
				g_structureActivePosition = g_selectionPosition;
				s->o.linkedID = STRUCTURE_INVALID;

				GUI_ChangeSelectionType(SELECTIONTYPE_PLACE);
			}
			break;

		case STR_ON_HOLD:
			s->o.flags.s.repairing = false;
			s->o.flags.s.onHold    = false;
			s->o.flags.s.upgrading = false;
			break;

		case STR_BUILD_IT:
			Structure_BuildObject(s, s->objectType);
			break;

		case STR_LAUNCH:
		case STR_FREMEN:
		case STR_SABOTEUR:
			Structure_ActivateSpecial(s);
			break;

		case STR_D_DONE:
			s->o.flags.s.onHold = true;
			break;
	}
	return false;
}
예제 #8
0
파일: structure.c 프로젝트: 166MMX/OpenDUNE
/**
 * Recount all Structures, ignoring the cache array. Also set the structureCount
 *  of all houses to zero.
 */
void Structure_Recount(void)
{
	uint16 index;
	PoolFindStruct find = { -1, -1, -1 };
	House *h = House_Find(&find);

	while (h != NULL) {
		h->unitCount = 0;
		h = House_Find(&find);
	}

	g_structureFindCount = 0;

	for (index = 0; index < STRUCTURE_INDEX_MAX_SOFT; index++) {
		Structure *s = Structure_Get_ByIndex(index);
		if (s->o.flags.s.used) g_structureFindArray[g_structureFindCount++] = s;
	}
}
예제 #9
0
파일: info.c 프로젝트: 166MMX/OpenDUNE
static uint32 SaveLoad_StructureActive(void *object, uint32 value, bool loading)
{
	VARIABLE_NOT_USED(object);

	if (loading) {
		if ((uint16)value != 0xFFFF) {
			g_structureActive = Structure_Get_ByIndex((uint16)value);
		} else {
			g_structureActive = NULL;
		}
		return 0;
	}

	if (g_structureActiveType != 0xFFFF) {
		return g_structureActive->o.index;
	} else {
		return 0xFFFF;
	}
}
예제 #10
0
파일: house.c 프로젝트: Haozerk/OpenDUNE
/**
 * Loop over all houses, preforming various of tasks.
 */
void GameLoop_House(void)
{
	PoolFindStruct find;
	House *h = NULL;
	bool tickHouse                = false;
	bool tickPowerMaintenance     = false;
	bool tickStarport             = false;
	bool tickReinforcement        = false;
	bool tickMissileCountdown     = false;
	bool tickStarportAvailability = false;

	if (g_debugScenario) return;

	if (s_tickHouseHouse <= g_timerGame) {
		tickHouse = true;
		s_tickHouseHouse = g_timerGame + 900;
	}

	if (g_tickHousePowerMaintenance <= g_timerGame) {
		tickPowerMaintenance = true;
		g_tickHousePowerMaintenance = g_timerGame + 10800;
	}

	if (s_tickHouseStarport <= g_timerGame) {
		tickStarport = true;
		s_tickHouseStarport = g_timerGame + 180;
	}

	if (s_tickHouseReinforcement <= g_timerGame) {
		tickReinforcement = true;
		s_tickHouseReinforcement = g_timerGame + (g_debugGame ? 60 : 600);
	}

	if (s_tickHouseMissileCountdown <= g_timerGame) {
		tickMissileCountdown = true;
		s_tickHouseMissileCountdown = g_timerGame + 60;
	}

	if (s_tickHouseStarportAvailability <= g_timerGame) {
		tickStarportAvailability = true;
		s_tickHouseStarportAvailability = g_timerGame + 1800;
	}

	if (tickMissileCountdown && g_houseMissileCountdown != 0) {
		g_houseMissileCountdown--;
		Sound_Output_Feedback(g_houseMissileCountdown + 41);

		if (g_houseMissileCountdown == 0) Unit_LaunchHouseMissile(Map_FindLocationTile(4, g_playerHouseID));
	}

	if (tickStarportAvailability) {
		uint16 type;

		/* Pick a random unit to increase starport availability */
		type = Tools_RandomLCG_Range(0, UNIT_MAX - 1);

		/* Increase how many of this unit is available via starport by one */
		if (g_starportAvailable[type] != 0 && g_starportAvailable[type] < 10) {
			if (g_starportAvailable[type] == -1) {
				g_starportAvailable[type] = 1;
			} else {
				g_starportAvailable[type]++;
			}
		}
	}

	if (tickReinforcement) {
		Unit *nu = NULL;
		int i;

		for (i = 0; i < 16; i++) {
			uint16 locationID;
			bool deployed;
			Unit *u;

			if (g_scenario.reinforcement[i].unitID == UNIT_INDEX_INVALID) continue;
			if (g_scenario.reinforcement[i].timeLeft == 0) continue;
			if (--g_scenario.reinforcement[i].timeLeft != 0) continue;

			u = Unit_Get_ByIndex(g_scenario.reinforcement[i].unitID);

			locationID = g_scenario.reinforcement[i].locationID;
			deployed   = false;

			if (locationID >= 4) {
				if (nu == NULL) {
					nu = Unit_Create(UNIT_INDEX_INVALID, UNIT_CARRYALL, u->o.houseID, Tile_UnpackTile(Map_FindLocationTile(Tools_Random_256() & 3, u->o.houseID)), 100);

					if (nu != NULL) {
						nu->o.flags.s.byScenario = true;
						Unit_SetDestination(nu, Tools_Index_Encode(Map_FindLocationTile(locationID, u->o.houseID), IT_TILE));
					}
				}

				if (nu != NULL) {
					u->o.linkedID = nu->o.linkedID;
					nu->o.linkedID = (uint8)u->o.index;
					nu->o.flags.s.inTransport = true;
					g_scenario.reinforcement[i].unitID = UNIT_INDEX_INVALID;
					deployed = true;
				} else {
					/* Failed to create carry-all, try again in a short moment */
					g_scenario.reinforcement[i].timeLeft = 1;
				}
			} else {
				deployed = Unit_SetPosition(u, Tile_UnpackTile(Map_FindLocationTile(locationID, u->o.houseID)));
			}

			if (deployed && g_scenario.reinforcement[i].repeat != 0) {
				tile32 tile;
				tile.x = 0xFFFF;
				tile.y = 0xFFFF;

				g_validateStrictIfZero++;
				u = Unit_Create(UNIT_INDEX_INVALID, u->o.type, u->o.houseID, tile, 0);
				g_validateStrictIfZero--;

				if (u != NULL) {
					g_scenario.reinforcement[i].unitID = u->o.index;
					g_scenario.reinforcement[i].timeLeft = g_scenario.reinforcement[i].timeBetween;
				}
			}
		}
	}

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

	while (true) {
		h = House_Find(&find);
		if (h == NULL) break;

		if (tickHouse) {
			/* ENHANCEMENT -- Originally this code was outside the house loop, which seems very odd.
			 *  This problem is considered to be so bad, that the original code has been removed. */
			if (h->index != g_playerHouseID) {
				if (h->creditsStorage < h->credits) {
					h->credits = h->creditsStorage;
				}
			} else {
				uint16 maxCredits = max(h->creditsStorage, g_playerCreditsNoSilo);
				if (h->credits > maxCredits) {
					h->credits = maxCredits;

					GUI_DisplayText(String_Get_ByIndex(STR_INSUFFICIENT_SPICE_STORAGE_AVAILABLE_SPICE_IS_LOST), 1);
				}
			}

			if (h->index == g_playerHouseID) {
				if (h->creditsStorage > g_playerCreditsNoSilo) {
					g_playerCreditsNoSilo = 0;
				}

				if (g_playerCreditsNoSilo == 0 && g_campaignID > 1 && h->credits != 0) {
					if (h->creditsStorage != 0 && ((h->credits * 256 / h->creditsStorage) > 200)) {
						GUI_DisplayText(String_Get_ByIndex(STR_SPICE_STORAGE_CAPACITY_LOW_BUILD_SILOS), 0);
					}
				}

				if (h->credits < 100 && g_playerCreditsNoSilo != 0) {
					GUI_DisplayText(String_Get_ByIndex(STR_CREDITS_ARE_LOW_HARVEST_SPICE_FOR_MORE_CREDITS), 0);
				}
			}
		}

		if (tickHouse) House_EnsureHarvesterAvailable((uint8)h->index);

		if (tickStarport && h->starportLinkedID != UNIT_INDEX_INVALID) {
			Unit *u = NULL;

			h->starportTimeLeft--;
			if ((int16)h->starportTimeLeft < 0) h->starportTimeLeft = 0;

			if (h->starportTimeLeft == 0) {
				Structure *s;

				s = Structure_Get_ByIndex(g_structureIndex);
				if (s->o.type == STRUCTURE_STARPORT && s->o.houseID == h->index) {
					u = Unit_CreateWrapper((uint8)h->index, UNIT_FRIGATE, Tools_Index_Encode(s->o.index, IT_STRUCTURE));
				} else {
					PoolFindStruct find2;

					find2.houseID = h->index;
					find2.index   = 0xFFFF;
					find2.type    = STRUCTURE_STARPORT;

					while (true) {
						s = Structure_Find(&find2);
						if (s == NULL) break;
						if (s->o.linkedID != 0xFF) continue;

						u = Unit_CreateWrapper((uint8)h->index, UNIT_FRIGATE, Tools_Index_Encode(s->o.index, IT_STRUCTURE));
						break;
					}
				}

				if (u != NULL) {
					u->o.linkedID = (uint8)h->starportLinkedID;
					h->starportLinkedID = UNIT_INDEX_INVALID;
					u->o.flags.s.inTransport = true;

					Sound_Output_Feedback(38);
				}

				h->starportTimeLeft = (u != NULL) ? g_table_houseInfo[h->index].starportDeliveryTime : 1;
			}
		}

		if (tickHouse) {
			House_CalculatePowerAndCredit(h);
			Structure_CalculateHitpointsMax(h);

			if (h->timerUnitAttack != 0) h->timerUnitAttack--;
			if (h->timerSandwormAttack != 0) h->timerSandwormAttack--;
			if (h->timerStructureAttack != 0) h->timerStructureAttack--;
			if (h->harvestersIncoming > 0 && Unit_CreateWrapper((uint8)h->index, UNIT_HARVESTER, 0) != NULL) h->harvestersIncoming--;
		}

		if (tickPowerMaintenance) {
			uint16 powerMaintenanceCost = (h->powerUsage / 32) + 1;
			h->credits -= min(h->credits, powerMaintenanceCost);
		}
	}
}