Esempio n. 1
0
// Check that we are still close to the start of the A* path,
// and the end of the path is close to our goal
static int AStarCloseToPath(
    AIGotoContext *c, Vec2i currentTile, Vec2i goalTile)
{
    Vec2i *pathTile;
    Vec2i *pathEnd;
    if (!c ||
            c->PathIndex >= (int)ASPathGetCount(c->Path) - 1) // at end of path
    {
        return 0;
    }
    // Check if we're too far from the current start of the path
    pathTile = ASPathGetNode(c->Path, c->PathIndex);
    if (CHEBYSHEV_DISTANCE(
                currentTile.x, currentTile.y, pathTile->x, pathTile->y) > 2)
    {
        return 0;
    }
    // Check if we're too far from the end of the path
    pathEnd = ASPathGetNode(c->Path, ASPathGetCount(c->Path) - 1);
    if (CHEBYSHEV_DISTANCE(
                goalTile.x, goalTile.y, pathEnd->x, pathEnd->y) > 0)
    {
        return 0;
    }
    return 1;
}
Esempio n. 2
0
static TActor *AIGetClosestActor(Vec2i from, int (*compFunc)(TActor *))
{
    // Search all the actors and find the closest one that
    // satisfies the condition
    TActor *closest = NULL;
    int minDistance = -1;
    for (int i = 0; i < (int)gActors.size; i++)
    {
        TActor *a = CArrayGet(&gActors, i);
        if (!a->isInUse || a->dead)
        {
            continue;
        }
        // Never target invulnerables or civilians
        if (a->flags & (FLAGS_INVULNERABLE | FLAGS_PENALTY))
        {
            continue;
        }
        if (compFunc(a))
        {
            int distance =
                CHEBYSHEV_DISTANCE(from.x, from.y, a->Pos.x, a->Pos.y);
            if (!closest || distance < minDistance)
            {
                minDistance = distance;
                closest = a;
            }
        }
    }
    return closest;
}
Esempio n. 3
0
static bool CanSeeAPlayer(const TActor *a)
{
    const Vec2i realPos = Vec2iFull2Real(a->Pos);
    CA_FOREACH(const PlayerData, p, gPlayerDatas)
    if (!IsPlayerAlive(p))
    {
        continue;
    }
    const TActor *player = ActorGetByUID(p->ActorUID);
    const Vec2i playerRealPos = Vec2iFull2Real(player->Pos);
    // Can see player if:
    // - Clear line of sight, and
    // - If they are close, or if facing and they are not too far
    if (!AIHasClearShot(realPos, playerRealPos))
    {
        continue;
    }
    const int distance = CHEBYSHEV_DISTANCE(
                             realPos.x, realPos.y, playerRealPos.x, playerRealPos.y);
    const bool isClose = distance < 16 * 4;
    const bool isNotTooFar = distance < 16 * 30;
    if (isClose ||
            (isNotTooFar && AIIsFacing(a, player->Pos, a->direction)))
    {
        return true;
    }
    CA_FOREACH_END()
    return false;
}
Esempio n. 4
0
static bool IsCloseToPlayer(const Vec2i fullPos, const int fullDistance)
{
    TActor *closestPlayer = AIGetClosestPlayer(fullPos);
    return closestPlayer && CHEBYSHEV_DISTANCE(
               fullPos.x, fullPos.y,
               closestPlayer->Pos.x, closestPlayer->Pos.y) < fullDistance;
}
Esempio n. 5
0
static bool CanSeeAPlayer(const TActor *a)
{
	const Vec2i realPos = Vec2iFull2Real(a->Pos);
	for (int i = 0; i < MAX_PLAYERS; i++)
	{
		if (!IsPlayerAlive(i))
		{
			continue;
		}
		const TActor *player = CArrayGet(&gActors, gPlayerIds[i]);
		const Vec2i playerRealPos = Vec2iFull2Real(player->Pos);
		// Can see player if:
		// - Clear line of sight, and
		// - If they are close, or if facing and they are not too far
		if (!AIHasClearShot(realPos, playerRealPos))
		{
			continue;
		}
		const int distance = CHEBYSHEV_DISTANCE(
			realPos.x, realPos.y, playerRealPos.x, playerRealPos.y);
		const bool isClose = distance < 16 * 4;
		const bool isNotTooFar = distance < 16 * 30;
		if (isClose ||
			(isNotTooFar && IsFacing(realPos, playerRealPos, a->direction)))
		{
			return true;
		}
	}
	return false;
}
Esempio n. 6
0
void SoundPlayAtPlusDistance(
	SoundDevice *device, Mix_Chunk *data,
	const Vec2i pos, const int plusDistance)
{
	int distance, bearing;
	Vec2i closestLeftEar, closestRightEar;
	Vec2i origin;

	// Find closest set of ears to the sound
	if (CHEBYSHEV_DISTANCE(
		pos.x, pos.y, device->earLeft1.x, device->earLeft1.y) <
		CHEBYSHEV_DISTANCE(
		pos.x, pos.y, device->earLeft2.x, device->earLeft2.y))
	{
		closestLeftEar = device->earLeft1;
	}
	else
	{
		closestLeftEar = device->earLeft2;
	}
	if (CHEBYSHEV_DISTANCE(
		pos.x, pos.y, device->earRight1.x, device->earRight1.y) <
		CHEBYSHEV_DISTANCE(
		pos.x, pos.y, device->earRight2.x, device->earRight2.y))
	{
		closestRightEar = device->earRight1;
	}
	else
	{
		closestRightEar = device->earRight2;
	}

	origin = CalcClosestPointOnLineSegmentToPoint(
		closestLeftEar, closestRightEar, pos);
	CalcChebyshevDistanceAndBearing(origin, pos, &distance, &bearing);
	HasClearLineData lineData;
	lineData.IsBlocked = IsPosNoSee;
	lineData.data = &gMap;
	bool isMuffled = false;
	if (!HasClearLineXiaolinWu(pos, origin, &lineData))
	{
		isMuffled = true;
	}
	SoundPlayAtPosition(
		&gSoundDevice, data, distance + plusDistance, bearing, isMuffled);
}
Esempio n. 7
0
static bool TryPlacePickup(HealthPickups *h)
{
	Vec2i size = Vec2iNew(HEALTH_W, HEALTH_H);
	// Attempt to place one in unexplored area
	for (int i = 0; i < 100; i++)
	{
		const Vec2i v = MapGenerateFreePosition(h->map, size);
		if (!Vec2iIsZero(v) && !MapGetTile(h->map, Vec2iToTile(v))->isVisited)
		{
			MapPlaceHealth(v);
			return true;
		}
	}
	// Attempt to place one in out-of-sight area
	for (int i = 0; i < 100; i++)
	{
		const Vec2i v = MapGenerateFreePosition(h->map, size);
		const Vec2i fullpos = Vec2iReal2Full(v);
		const TActor *closestPlayer = AIGetClosestPlayer(fullpos);
		if (!Vec2iIsZero(v) &&
			(!closestPlayer || CHEBYSHEV_DISTANCE(
			fullpos.x, fullpos.y,
			closestPlayer->Pos.x, closestPlayer->Pos.y) >= 256 * 150))
		{
			MapPlaceHealth(v);
			return true;
		}
	}
	// Attempt to place one anyway
	for (int i = 0; i < 100; i++)
	{
		const Vec2i v = MapGenerateFreePosition(h->map, size);
		if (!Vec2iIsZero(v))
		{
			MapPlaceHealth(v);
			return true;
		}
	}
	return false;
}
Esempio n. 8
0
void CalcChebyshevDistanceAndBearing(
	Vector2i origin, Vector2i target, int *distance, int *bearing)
{
	// short circuit if origin and target same
	if (origin.x == target.x && origin.y == target.y)
	{
		*distance = 0;
		*bearing = 0;
	}
	else
	{
		double angle;
		*distance = CHEBYSHEV_DISTANCE(origin.x, origin.y, target.x, target.y);
		angle = ToDegrees(atan2(target.y - origin.y, target.x - origin.x));
		// convert angle to bearings
		// first rotate so 0 angle = 0 bearing
		angle -= 90.0;
		// then reflect about Y axis
		angle = 360 - angle;
		*bearing = (int)floor(angle + 0.5);
	}
}
Esempio n. 9
0
TActor *AIGetClosestPlayer(Vec2i fullpos)
{
    int i;
    int minDistance = -1;
    TActor *closestPlayer = NULL;
    for (i = 0; i < gOptions.numPlayers; i++)
    {
        if (IsPlayerAlive(i))
        {
            TActor *p = CArrayGet(&gActors, gPlayerIds[i]);
            Vec2i pPos = Vec2iFull2Real(p->Pos);
            int distance = CHEBYSHEV_DISTANCE(
                               fullpos.x, fullpos.y, pPos.x, pPos.y);
            if (!closestPlayer || distance < minDistance)
            {
                closestPlayer = p;
                minDistance = distance;
            }
        }
    }
    return closestPlayer;
}
Esempio n. 10
0
static void PlaceBaddie(TActor *actor)
{
	int hasPlaced = 0;
	int i;
	for (i = 0; i < 100; i++)	// Don't try forever trying to place baddie
	{
		// Try spawning out of players' sights
		actor->Pos.x = (rand() % (gMap.Size.x * TILE_WIDTH)) << 8;
		actor->Pos.y = (rand() % (gMap.Size.y * TILE_HEIGHT)) << 8;
		TActor *closestPlayer = AIGetClosestPlayer(actor->Pos);
		if (closestPlayer && CHEBYSHEV_DISTANCE(
			actor->Pos.x, actor->Pos.y,
			closestPlayer->Pos.x, closestPlayer->Pos.y) >= 256 * 150 &&
			IsActorPositionValid(actor))
		{
			hasPlaced = 1;
			break;
		}
	}
	// Keep trying, but this time try spawning anywhere, even close to player
	while (!hasPlaced)
	{
		actor->Pos.x = (rand() % (gMap.Size.x * TILE_WIDTH)) << 8;
		actor->Pos.y = (rand() % (gMap.Size.y * TILE_HEIGHT)) << 8;
		if (IsActorPositionValid(actor))
		{
			hasPlaced = 1;
			break;
		}
	}

	ActorInit(actor);
	if (!(actor->flags & FLAGS_SLEEPALWAYS) &&
		rand() % 100 < gBaddieCount)
	{
		actor->flags &= ~FLAGS_SLEEPING;
	}
}
Esempio n. 11
0
NetMsgVec2i PlaceBaddie(Map *map)
{
	// Don't try forever trying to place baddie
	for (int i = 0; i < 100; i++)
	{
		// Try spawning out of players' sights
		const Vec2i pos = Vec2iReal2Full(Vec2iNew(
			rand() % (map->Size.x * TILE_WIDTH),
			rand() % (map->Size.y * TILE_HEIGHT)));
		const TActor *closestPlayer = AIGetClosestPlayer(pos);
		if (closestPlayer && CHEBYSHEV_DISTANCE(
			pos.x, pos.y,
			closestPlayer->Pos.x, closestPlayer->Pos.y) >= 256 * 150 &&
			MapIsTileAreaClear(map, pos, Vec2iNew(ACTOR_W, ACTOR_H)))
		{
			NetMsgVec2i posNet;
			posNet.x = pos.x;
			posNet.y = pos.y;
			return posNet;
		}
	}
	// Keep trying, but this time try spawning anywhere,
	// even close to player
	for (;;)
	{
		const Vec2i pos = Vec2iReal2Full(Vec2iNew(
			rand() % (map->Size.x * TILE_WIDTH),
			rand() % (map->Size.y * TILE_HEIGHT)));
		if (MapIsTileAreaClear(map, pos, Vec2iNew(ACTOR_W, ACTOR_H)))
		{
			NetMsgVec2i posNet;
			posNet.x = pos.x;
			posNet.y = pos.y;
			return posNet;
		}
	}
}