Beispiel #1
0
/**
 * Link two variable4 values to eachother, and clean up existing values if
 *  needed.
 * @param encodedFrom From where the link goes.
 * @param encodedTo To where the link goes.
 */
void Object_Script_Variable4_Link(uint16 encodedFrom, uint16 encodedTo)
{
	Object* objectFrom;
	Object* objectTo;

	if (!Tools_Index_IsValid(encodedFrom))
		return;
	if (!Tools_Index_IsValid(encodedTo))
		return;

	objectFrom = Tools_Index_GetObject(encodedFrom);
	objectTo = Tools_Index_GetObject(encodedTo);

	if (objectFrom == NULL)
		return;
	if (objectTo == NULL)
		return;

	if (objectFrom->script.variables[4] != objectTo->script.variables[4])
	{
		Object_Script_Variable4_Clear(objectFrom);
		Object_Script_Variable4_Clear(objectTo);
	}
	if (objectFrom->script.variables[4] != 0)
		return;

	Object_Script_Variable4_Set(objectFrom, encodedTo);
	Object_Script_Variable4_Set(objectTo, encodedFrom);

	return;
}
Beispiel #2
0
/**
 * Get information about the unit, like hitpoints, current target, etc.
 *
 * Stack: 1 - Which information you would like.
 *
 * @param script The script engine to operate on.
 * @return The information you requested.
 */
uint16 Script_Unit_GetInfo(ScriptEngine *script)
{
	const UnitInfo *ui;
	Unit *u;

	u = g_scriptCurrentUnit;
	ui = &g_table_unitInfo[u->o.type];

	switch (STACK_PEEK(1)) {
		case 0x00: return u->o.hitpoints * 256 / ui->o.hitpoints;
		case 0x01: return Tools_Index_IsValid(u->targetMove) ? u->targetMove : 0;
		case 0x02: return ui->fireDistance << 8;
		case 0x03: return u->o.index;
		case 0x04: return u->orientation[0].current;
		case 0x05: return u->targetAttack;
		case 0x06:
			if (u->originEncoded == 0 || u->o.type == UNIT_HARVESTER) Unit_FindClosestRefinery(u);
			return u->originEncoded;
		case 0x07: return u->o.type;
		case 0x08: return Tools_Index_Encode(u->o.index, IT_UNIT);
		case 0x09: return u->movingSpeed;
		case 0x0A: return abs(u->orientation[0].target - u->orientation[0].current);
		case 0x0B: return u->currentDestination.tile == 0 ? 0 : 1;
		case 0x0C: return u->fireDelay == 0 ? 1 : 0;
		case 0x0D: return ui->flags.explodeOnDeath;
		case 0x0E: return Unit_GetHouseID(u);
		case 0x0F: return u->o.flags.s.byScenario ? 1 : 0;
		case 0x10: return u->orientation[ui->o.flags.hasTurret ? 1 : 0].current;
		case 0x11: return abs(u->orientation[ui->o.flags.hasTurret ? 1 : 0].target - u->orientation[ui->o.flags.hasTurret ? 1 : 0].current);
		case 0x12: return (ui->movementType & 0x40) == 0 ? 0 : 1;
		case 0x13: return (u->o.seenByHouses & (1 << g_playerHouseID)) == 0 ? 0 : 1;
		default:   return 0;
	}
}
Beispiel #3
0
/**
 * Set a new target, and rotate towards him if needed.
 *
 * Stack: 1 - An encoded tile of the unit/tile to target.
 *
 * @param script The script engine to operate on.
 * @return The new target.
 */
uint16 Script_Unit_SetTarget(ScriptEngine *script)
{
	Unit *u;
	uint16 target;
	tile32 tile;
	int8 orientation;

	u = g_scriptCurrentUnit;

	target = STACK_PEEK(1);

	if (target == 0 || !Tools_Index_IsValid(target)) {
		u->targetAttack = 0;
		return 0;
	}

	tile = Tools_Index_GetTile(target);

	orientation = Tile_GetDirection(u->o.position, tile);

	u->targetAttack = target;
	if (!g_table_unitInfo[u->o.type].o.flags.hasTurret) {
		u->targetMove = target;
		Unit_SetOrientation(u, orientation, false, 0);
	}
	Unit_SetOrientation(u, orientation, false, 1);

	return u->targetAttack;
}
Beispiel #4
0
/**
 * Set the new destination of the unit.
 *
 * Stack: 1 - An encoded index where to move to.
 *
 * @param script The script engine to operate on.
 * @return The value 0. Always.
 */
uint16 Script_Unit_SetDestination(ScriptEngine *script)
{
	Unit *u;
	uint16 encoded;

	u = g_scriptCurrentUnit;
	encoded = STACK_PEEK(1);

	if (encoded == 0 || !Tools_Index_IsValid(encoded)) {
		u->targetMove = 0;
		return 0;
	}

	if (u->o.type == UNIT_HARVESTER) {
		Structure *s;

		s = Tools_Index_GetStructure(encoded);
		if (s == NULL) {
			u->targetMove = encoded;
			u->route[0] = 0xFF;
			return 0;
		}

		if (s->o.script.variables[4] != 0) return 0;
	}

	Unit_SetDestination(u, encoded);
	return 0;
}
Beispiel #5
0
/**
 * Rotate the unit to aim at the enemy.
 *
 * Stack: *none*.
 *
 * @param script The script engine to operate on.
 * @return 0 if the enemy is no longer there or if we are looking at him, 1 otherwise.
 */
uint16 Script_Unit_Rotate(ScriptEngine *script)
{
	const UnitInfo *ui;
	Unit *u;
	uint16 index;
	int8 current;
	tile32 tile;
	int8 orientation;

	VARIABLE_NOT_USED(script);

	u = g_scriptCurrentUnit;
	ui = &g_table_unitInfo[u->o.type];

	if (ui->movementType != MOVEMENT_WINGER && u->currentDestination.tile != 0) return 1;

	index = ui->o.flags.hasTurret ? 1 : 0;

	/* Check if we are already rotating */
	if (u->orientation[index].speed != 0) return 1;
	current = u->orientation[index].current;

	if (!Tools_Index_IsValid(u->targetAttack)) return 0;

	/* Check where we should rotate to */
	tile = Tools_Index_GetTile(u->targetAttack);
	orientation = Tile_GetDirection(u->o.position, tile);

	/* If we aren't already looking at it, rotate */
	if (orientation == current) return 0;
	Unit_SetOrientation(u, orientation, false, index);

	return 1;
}
Beispiel #6
0
/**
 * Calculate the route to a tile.
 *
 * Stack: 1 - An encoded tile to calculate the route to.
 *
 * @param script The script engine to operate on.
 * @return 0 if we arrived on location, 1 otherwise.
 */
uint16 Script_Unit_CalculateRoute(ScriptEngine *script)
{
	Unit *u;
	uint16 encoded;
	uint16 packedSrc;
	uint16 packedDst;

	u = g_scriptCurrentUnit;
	encoded = STACK_PEEK(1);

	if (u->currentDestination.tile != 0 || !Tools_Index_IsValid(encoded)) return 1;

	packedSrc = Tile_PackTile(u->o.position);
	packedDst = Tools_Index_GetPackedTile(encoded);

	if (packedDst == packedSrc) {
		u->route[0] = 0xFF;
		u->targetMove = 0;
		return 0;
	}

	if (u->route[0] == 0xFF) {
		Pathfinder_Data res;
		uint8 buffer[42];

		res = Script_Unit_Pathfinder(packedSrc, packedDst, buffer, 40);

		memcpy(u->route, res.buffer, min(res.routeSize, 14));

		if (u->route[0] == 0xFF) {
			u->targetMove = 0;
			if (u->o.type == UNIT_SANDWORM) {
				script->delay = 720;
			}
		}
	} else {
		uint16 distance;

		distance = Tile_GetDistancePacked(packedDst, packedSrc);
		if (distance < 14) u->route[distance] = 0xFF;
	}

	if (u->route[0] == 0xFF) return 1;

	if (u->orientation[0].current != (int8)(u->route[0] * 32)) {
		Unit_SetOrientation(u, (int8)(u->route[0] * 32), false, 0);
		return 1;
	}

	if (!Unit_StartMovement(u)) {
		u->route[0] = 0xFF;
		return 0;
	}

	memmove(&u->route[0], &u->route[1], 13);
	u->route[13] = 0xFF;
	return 1;
}
Beispiel #7
0
/**
 * Find the direction a tile is, seen from the structure. If the tile is
 *  invalid it gives the direction the structure is currently looking at.
 *
 * Stack: 1 - Tile to get the direction to, or the current direction of the
 *   structure in case the tile is invalid.
 *
 * @param script The script engine to operate on.
 * @return The direction (value between 0 and 7, shifted to the left with 5).
 */
uint16 Script_Structure_GetDirection(ScriptEngine *script)
{
	Structure *s;
	tile32 tile;
	uint16 encoded;

	s = g_scriptCurrentStructure;
	encoded = STACK_PEEK(1);

	if (!Tools_Index_IsValid(encoded)) return s->rotationSpriteDiff << 5;

	tile = Tools_Index_GetTile(encoded);

	return Orientation_Orientation256ToOrientation8(Tile_GetDirection(s->o.position, tile)) << 5;
}
Beispiel #8
0
/**
 * Unknown function 11B9.
 *
 * Stack: 1 - Encoded tile.
 *
 * @param script The script engine to operate on.
 * @return unknown.
 */
uint16 Script_Structure_Unknown11B9(ScriptEngine *script)
{
	uint16 encoded;
	Unit *u;

	encoded = STACK_PEEK(1);

	if (!Tools_Index_IsValid(encoded)) return 0;
	if (Tools_Index_GetType(encoded) != IT_UNIT) return 0;

	u = Tools_Index_GetUnit(encoded);
	if (u == NULL) return 0;

	Object_Script_Variable4_Clear(&u->o);
	u->targetMove = 0;

	return 0;
}
Beispiel #9
0
/**
 * Get the direction to a tile or our current direction.
 *
 * Stack: 1 - An encoded tile to get the direction to.
 *
 * @param script The script engine to operate on.
 * @return The direction to the encoded tile if valid, otherwise our current orientation.
 */
uint16 Script_Unit_GetOrientation(ScriptEngine *script)
{
	Unit *u;
	uint16 encoded;

	u = g_scriptCurrentUnit;
	encoded = STACK_PEEK(1);

	if (Tools_Index_IsValid(encoded)) {
		tile32 tile;

		tile = Tools_Index_GetTile(encoded);

		return Tile_GetDirection(u->o.position, tile);
	}

	return u->orientation[0].current;
}
Beispiel #10
0
/**
 * Set the current destination of a Unit, bypassing any pathfinding.
 * It is wise to only use this function on Carry-Alls.
 *
 * Stack: 1 - An encoded tile, the destination.
 *
 * @param script The script engine to operate on.
 * @return The value 0. Always.
 */
uint16 Script_Unit_SetDestinationDirect(ScriptEngine *script)
{
	Unit *u;
	uint16 encoded;

	encoded = STACK_PEEK(1);

	if (!Tools_Index_IsValid(encoded)) return 0;

	u = g_scriptCurrentUnit;

	if (u->currentDestination.tile == 0 || g_table_unitInfo[u->o.type].flags.isNormalUnit) {
		u->currentDestination = Tools_Index_GetTile(encoded);
	}

	Unit_SetOrientation(u, Tile_GetDirection(u->o.position, u->currentDestination), false, 0);

	return 0;
}
Beispiel #11
0
/**
 * Makes the current unit fire a bullet (or eat its target).
 *
 * Stack: *none*.
 *
 * @param script The script engine to operate on.
 * @return The value 1 if the current unit fired/eat, 0 otherwise.
 */
uint16 Script_Unit_Fire(ScriptEngine *script)
{
	const UnitInfo *ui;
	Unit *u;
	uint16 target;
	UnitType typeID;
	uint16 distance;
	bool fireTwice;
	uint16 damage;

	u = g_scriptCurrentUnit;

	target = u->targetAttack;
	if (target == 0 || !Tools_Index_IsValid(target)) return 0;

	if (u->o.type != UNIT_SANDWORM && target == Tools_Index_Encode(Tile_PackTile(u->o.position), IT_TILE)) u->targetAttack = 0;

	if (u->targetAttack != target) {
		Unit_SetTarget(u, target);
		return 0;
	}

	ui = &g_table_unitInfo[u->o.type];

	if (u->o.type != UNIT_SANDWORM && u->orientation[ui->o.flags.hasTurret ? 1 : 0].speed != 0) return 0;

	if (Tools_Index_GetType(target) == IT_TILE && Object_GetByPackedTile(Tools_Index_GetPackedTile(target)) != NULL) Unit_SetTarget(u, target);

	if (u->fireDelay != 0) return 0;

	distance = Object_GetDistanceToEncoded(&u->o, target);

	if ((int16)(ui->fireDistance << 8) < (int16)distance) return 0;

	if (u->o.type != UNIT_SANDWORM && (Tools_Index_GetType(target) != IT_UNIT || g_table_unitInfo[Tools_Index_GetUnit(target)->o.type].movementType != MOVEMENT_WINGER)) {
		int16 diff = 0;
		int8 orientation;

		orientation = Tile_GetDirection(u->o.position, Tools_Index_GetTile(target));

		diff = abs(u->orientation[ui->o.flags.hasTurret ? 1 : 0].current - orientation);
		if (ui->movementType == MOVEMENT_WINGER) diff /= 8;

		if (diff >= 8) return 0;
	}

	damage = ui->damage;
	typeID = ui->bulletType;

	fireTwice = ui->flags.firesTwice && u->o.hitpoints > ui->o.hitpoints / 2;

	if ((u->o.type == UNIT_TROOPERS || u->o.type == UNIT_TROOPER) && (int16)distance > 512) typeID = UNIT_MISSILE_TROOPER;

	switch (typeID) {
		case UNIT_SANDWORM: {
			Unit *u2;

			Unit_UpdateMap(0, u);

			u2 = Tools_Index_GetUnit(target);

			if (u2 != NULL) {
				u2->o.script.variables[1] = 0xFFFF;
				Unit_RemovePlayer(u2);
				Unit_HouseUnitCount_Remove(u2);
				Unit_Remove(u2);
			}

			Map_MakeExplosion(ui->explosionType, u->o.position, 0, 0);

			Voice_PlayAtTile(63, u->o.position);

			Unit_UpdateMap(1, u);

			u->amount--;

			script->delay = 12;

			if ((int8)u->amount < 1) Unit_SetAction(u, ACTION_DIE);
		} break;

		case UNIT_MISSILE_TROOPER:
			damage -= damage / 4;
			/* FALL-THROUGH */

		case UNIT_MISSILE_ROCKET:
		case UNIT_MISSILE_TURRET:
		case UNIT_MISSILE_DEVIATOR:
		case UNIT_BULLET:
		case UNIT_SONIC_BLAST: {
			Unit *bullet;

			bullet = Unit_CreateBullet(u->o.position, typeID, Unit_GetHouseID(u), damage, target);

			if (bullet == NULL) return 0;

			bullet->originEncoded = Tools_Index_Encode(u->o.index, IT_UNIT);

			Voice_PlayAtTile(ui->bulletSound, u->o.position);

			Unit_Deviation_Decrease(u, 20);
		} break;

		default: break;
	}

	u->fireDelay = Tools_AdjustToGameSpeed(ui->fireDelay * 2, 1, 0xFFFF, true);

	if (fireTwice) {
		u->o.flags.s.fireTwiceFlip = !u->o.flags.s.fireTwiceFlip;
		if (u->o.flags.s.fireTwiceFlip) u->fireDelay = Tools_AdjustToGameSpeed(5, 1, 10, true) & 0xFF;
	} else {
		u->o.flags.s.fireTwiceFlip = false;
	}

	u->fireDelay += Tools_Random_256() & 1;

	Unit_UpdateMap(2, u);

	return 1;
}