示例#1
0
// Give a Droid an order with a stat
bool scrOrderDroidStatsLoc(void)
{
	DROID			*psDroid;
	DROID_ORDER		order;
	SDWORD			x,y, statIndex;
	BASE_STATS		*psStats;

	if (!stackPopParams(5, ST_DROID, &psDroid, VAL_INT, &order, ST_STRUCTURESTAT, &statIndex,
						   VAL_INT, &x, VAL_INT, &y))
	{
		return false;
	}

	if (statIndex < 0 || statIndex >= (SDWORD)numStructureStats)
	{
		ASSERT( false, "Invalid structure stat" );
		return false;
	}

	ASSERT_OR_RETURN( false, statIndex < numStructureStats, "Invalid range referenced for numStructureStats, %d > %d", statIndex, numStructureStats);
	psStats = (asStructureStats + statIndex);

	ASSERT_OR_RETURN( false, psDroid != NULL, "Invalid Unit pointer" );
	ASSERT_OR_RETURN( false, psStats != NULL, "Invalid object pointer" );
	if (psDroid == NULL)
	{
		return false;
	}

	if ((x < 0) || (x > (SDWORD)mapWidth*TILE_UNITS) ||
		(y < 0) || (y > (SDWORD)mapHeight*TILE_UNITS))
	{
		ASSERT( false, "Invalid location" );
		return false;
	}

	if (order != DORDER_BUILD)
	{
		ASSERT( false, "Invalid order" );
		return false;
	}

	// Don't allow scripts to order structure builds if players structure
	// limit has been reached.
	if (!IsPlayerStructureLimitReached(psDroid->player))
	{
		// HACK: FIXME: Looks like a script error in the player*.slo files
		// buildOnExactLocation() which references previously destroyed buildings from
		// _stat = rebuildStructStat[_count]  causes this.
		if (strcmp(psStats->pName, "A0ADemolishStructure") == 0)
		{
			// I don't feel like spamming a ASSERT here, we *know* it is a issue. 
			return true;
		}

		orderDroidStatsLocDir(psDroid, order, psStats, x, y, 0, ModeQueue);
	}

	return true;
}
示例#2
0
// not a direct script function but a helper for scrSkDefenseLocation and scrSkDefenseLocationB
static bool defenseLocation(bool variantB)
{
	SDWORD		*pX, *pY, statIndex, statIndex2;
	UDWORD		x, y, gX, gY, dist, player, nearestSoFar, count;
	GATEWAY		*psGate, *psChosenGate;
	DROID		*psDroid;
	UDWORD		x1, x2, x3, x4, y1, y2, y3, y4;
	bool		noWater;
	UDWORD      minCount;
	UDWORD      offset;

	if (!stackPopParams(6,
	        VAL_REF | VAL_INT, &pX,
	        VAL_REF | VAL_INT, &pY,
	        ST_STRUCTURESTAT, &statIndex,
	        ST_STRUCTURESTAT, &statIndex2,
	        ST_DROID, &psDroid,
	        VAL_INT, &player))
	{
		debug(LOG_ERROR, "defenseLocation: failed to pop");
		return false;
	}

	if (player >= MAX_PLAYERS)
	{
		ASSERT(false, "defenseLocation:player number is too high");
		return false;
	}

	ASSERT_OR_RETURN(false, statIndex < numStructureStats, "Invalid range referenced for numStructureStats, %d > %d", statIndex, numStructureStats);

	ASSERT_OR_RETURN(false, statIndex2 < numStructureStats, "Invalid range referenced for numStructureStats, %d > %d", statIndex2, numStructureStats);
	STRUCTURE_STATS *psWStats = (asStructureStats + statIndex2);

	// check for wacky coords.
	if (*pX < 0
	    ||	*pX > world_coord(mapWidth)
	    ||	*pY < 0
	    ||	*pY > world_coord(mapHeight)
	   )
	{
		goto failed;
	}

	x = map_coord(*pX);					// change to tile coords.
	y = map_coord(*pY);

	// go down the gateways, find the nearest gateway with >1 empty tiles
	nearestSoFar = UDWORD_MAX;
	psChosenGate = NULL;
	for (psGate = gwGetGateways(); psGate; psGate = psGate->psNext)
	{
		if (auxTile(psGate->x1, psGate->y1, player) & AUXBITS_THREAT)
		{
			continue;	// enemy can shoot there, not safe to build
		}
		count = 0;
		noWater = true;
		// does it have >1 tile unoccupied.
		if (psGate->x1 == psGate->x2)
		{
			// vert
			//skip gates that are too short
			if (variantB && (psGate->y2 - psGate->y1) <= 2)
			{
				continue;
			}
			gX = psGate->x1;
			for (gY = psGate->y1; gY <= psGate->y2; gY++)
			{
				if (! TileIsOccupied(mapTile(gX, gY)))
				{
					count++;
				}
				if (terrainType(mapTile(gX, gY)) == TER_WATER)
				{
					noWater = false;
				}
			}
		}
		else
		{
			// horiz
			//skip gates that are too short
			if (variantB && (psGate->x2 - psGate->x1) <= 2)
			{
				continue;
			}
			gY = psGate->y1;
			for (gX = psGate->x1; gX <= psGate->x2; gX++)
			{
				if (! TileIsOccupied(mapTile(gX, gY)))
				{
					count++;
				}
				if (terrainType(mapTile(gX, gY)) == TER_WATER)
				{
					noWater = false;
				}
			}
		}
		if (variantB)
		{
			minCount = 2;
		}
		else
		{
			minCount = 1;
		}
		if (count > minCount && noWater)	//<NEW> min 2 tiles
		{
			// ok it's free. Is it the nearest one yet?
			/* Get gateway midpoint */
			gX = (psGate->x1 + psGate->x2) / 2;
			gY = (psGate->y1 + psGate->y2) / 2;
			/* Estimate the distance to it */
			dist = iHypot(x - gX, y - gY);
			/* Is it best we've found? */
			if (dist < nearestSoFar && dist < 30)
			{
				/* Yes, then keep a record of it */
				nearestSoFar = dist;
				psChosenGate = psGate;
			}
		}
	}

	if (!psChosenGate)	// we have a gateway.
	{
		goto failed;
	}

	// find an unnocupied tile on that gateway.
	if (psChosenGate->x1 == psChosenGate->x2)
	{
		// vert
		gX = psChosenGate->x1;
		for (gY = psChosenGate->y1; gY <= psChosenGate->y2; gY++)
		{
			if (! TileIsOccupied(mapTile(gX, gY)))
			{
				y = gY;
				x = gX;
				break;
			}
		}
	}
	else
	{
		// horiz
		gY = psChosenGate->y1;
		for (gX = psChosenGate->x1; gX <= psChosenGate->x2; gX++)
		{
			if (! TileIsOccupied(mapTile(gX, gY)))
			{
				y = gY;
				x = gX;
				break;
			}
		}
	}

	// back to world coords and store result.
	*pX = world_coord(x) + (TILE_UNITS / 2);		// return centre of tile.
	*pY = world_coord(y) + (TILE_UNITS / 2);

	scrFunctionResult.v.bval = true;
	if (!stackPushResult(VAL_BOOL, &scrFunctionResult))		// success
	{
		return false;
	}


	// order the droid to build two walls, one either side of the gateway.
	// or one in the case of a 2 size gateway.

	//find center of the gateway
	x = (psChosenGate->x1 + psChosenGate->x2) / 2;
	y = (psChosenGate->y1 + psChosenGate->y2) / 2;

	//find start pos of the gateway
	x1 = world_coord(psChosenGate->x1) + (TILE_UNITS / 2);
	y1 = world_coord(psChosenGate->y1) + (TILE_UNITS / 2);

	if (variantB)
	{
		offset = 2;
	}
	else
	{
		offset = 1;
	}
	if (psChosenGate->x1 == psChosenGate->x2)	//vert
	{
		x2 = x1;	//vert: end x pos of the first section = start x pos
		y2 = world_coord(y - 1) + TILE_UNITS / 2;	//start y loc of the first sec
		x3 = x1;
		y3 = world_coord(y + offset) + TILE_UNITS / 2;
	}
	else		//hor
	{
		x2 = world_coord(x - 1) + TILE_UNITS / 2;
		y2 = y1;
		x3 = world_coord(x + offset) + TILE_UNITS / 2;
		y3 = y1;

	}
	//end coords of the second section
	x4 = world_coord(psChosenGate->x2) + TILE_UNITS / 2;
	y4 = world_coord(psChosenGate->y2) + TILE_UNITS / 2;

	// first section.
	if (x1 == x2 && y1 == y2)	//first sec is 1 tile only: ((2 tile gate) or (3 tile gate and first sec))
	{
		orderDroidStatsLocDir(psDroid, DORDER_BUILD, psWStats, x1, y1, 0, ModeQueue);
	}
	else
	{
		orderDroidStatsTwoLocDir(psDroid, DORDER_LINEBUILD, psWStats,  x1, y1, x2, y2, 0, ModeQueue);
	}

	// second section
	if (x3 == x4 && y3 == y4)
	{
		orderDroidStatsLocDirAdd(psDroid, DORDER_BUILD, psWStats, x3, y3, 0);
	}
	else
	{
		orderDroidStatsTwoLocDirAdd(psDroid, DORDER_LINEBUILD, psWStats,  x3, y3, x4, y4, 0);
	}

	return true;

failed:
	scrFunctionResult.v.bval = false;
	if (!stackPushResult(VAL_BOOL, &scrFunctionResult))		// failed!
	{
		return false;
	}
	return true;
}