Пример #1
0
void CommandBadGuys(int ticks)
{
    int count = 0;
    int delayModifier;
    int rollLimit;

    switch (ConfigGetEnum(&gConfig, "Game.Difficulty"))
    {
    case DIFFICULTY_VERYEASY:
        delayModifier = 4;
        rollLimit = 300;
        break;
    case DIFFICULTY_EASY:
        delayModifier = 2;
        rollLimit = 200;
        break;
    case DIFFICULTY_HARD:
        delayModifier = 1;
        rollLimit = 75;
        break;
    case DIFFICULTY_VERYHARD:
        delayModifier = 1;
        rollLimit = 50;
        break;
    default:
        delayModifier = 1;
        rollLimit = 100;
        break;
    }

    CA_FOREACH(TActor, actor, gActors)
    if (!actor->isInUse)
    {
        continue;
    }
    const CharBot *bot = ActorGetCharacter(actor)->bot;
    if (!(actor->PlayerUID >= 0 || (actor->flags & FLAGS_PRISONER)))
    {
        if ((actor->flags & (FLAGS_VICTIM | FLAGS_GOOD_GUY)) != 0)
        {
            gAreGoodGuysPresent = 1;
        }

        count++;
        int cmd = 0;

        // Wake up if it can see a player
        if ((actor->flags & FLAGS_SLEEPING) &&
                actor->aiContext->Delay == 0)
        {
            if (CanSeeAPlayer(actor))
            {
                actor->flags &= ~FLAGS_SLEEPING;
                ActorSetAIState(actor, AI_STATE_NONE);
            }
            actor->aiContext->Delay = bot->actionDelay * delayModifier;
            // Randomly change direction
            int newDir = (int)actor->direction + ((rand() % 2) * 2 - 1);
            if (newDir < (int)DIRECTION_UP)
            {
                newDir = (int)DIRECTION_UPLEFT;
            }
            if (newDir == (int)DIRECTION_COUNT)
            {
                newDir = (int)DIRECTION_UP;
            }
            cmd = DirectionToCmd((int)newDir);
        }
        // Go to sleep if the player's too far away
        if (!(actor->flags & FLAGS_SLEEPING) &&
                actor->aiContext->Delay == 0 &&
                !(actor->flags & FLAGS_AWAKEALWAYS))
        {
            if (!IsCloseToPlayer(actor->Pos, (40 * 16) << 8))
            {
                actor->flags |= FLAGS_SLEEPING;
                ActorSetAIState(actor, AI_STATE_IDLE);
            }
        }

        if (!actor->dead && !(actor->flags & FLAGS_SLEEPING))
        {
            bool bypass = false;
            const int roll = rand() % rollLimit;
            if (actor->flags & FLAGS_FOLLOWER)
            {
                if (IsCloseToPlayer(actor->Pos, 32 << 8))
                {
                    cmd = 0;
                    ActorSetAIState(actor, AI_STATE_IDLE);
                }
                else
                {
                    cmd = AIGoto(
                              actor, AIGetClosestPlayerPos(actor->Pos), true);
                    ActorSetAIState(actor, AI_STATE_FOLLOW);
                }
            }
            else if (!!(actor->flags & FLAGS_SNEAKY) &&
                     !!(actor->flags & FLAGS_VISIBLE) &&
                     DidPlayerShoot())
            {
                cmd = AIHuntClosest(actor) | CMD_BUTTON1;
                if (actor->flags & FLAGS_RUNS_AWAY)
                {
                    // Turn back and shoot for running away characters
                    cmd = AIReverseDirection(cmd);
                }
                bypass = true;
                ActorSetAIState(actor, AI_STATE_HUNT);
            }
            else if (actor->flags & FLAGS_DETOURING)
            {
                cmd = BrightWalk(actor, roll);
                ActorSetAIState(actor, AI_STATE_TRACK);
            }
            else if (actor->aiContext->Delay > 0)
            {
                cmd = actor->lastCmd & ~CMD_BUTTON1;
            }
            else
            {
                if (roll < bot->probabilityToTrack)
                {
                    cmd = AIHuntClosest(actor);
                    ActorSetAIState(actor, AI_STATE_HUNT);
                }
                else if (roll < bot->probabilityToMove)
                {
                    cmd = DirectionToCmd(rand() & 7);
                    ActorSetAIState(actor, AI_STATE_TRACK);
                }
                else
                {
                    cmd = 0;
                }
                actor->aiContext->Delay = bot->actionDelay * delayModifier;
            }
            if (!bypass)
            {
                if (WillFire(actor, roll))
                {
                    cmd |= CMD_BUTTON1;
                    if (!!(actor->flags & FLAGS_FOLLOWER) &&
                            (actor->flags & FLAGS_GOOD_GUY))
                    {
                        // Shoot in a random direction away
                        for (int j = 0; j < 10; j++)
                        {
                            direction_e d =
                                (direction_e)(rand() % DIRECTION_COUNT);
                            if (!IsFacingPlayer(actor, d))
                            {
                                cmd = DirectionToCmd(d) | CMD_BUTTON1;
                                break;
                            }
                        }
                    }
                    if (actor->flags & FLAGS_RUNS_AWAY)
                    {
                        // Turn back and shoot for running away characters
                        cmd |= AIReverseDirection(AIHuntClosest(actor));
                    }
                    ActorSetAIState(actor, AI_STATE_HUNT);
                }
                else
                {
                    if ((actor->flags & FLAGS_VISIBLE) == 0)
                    {
                        // I think this is some hack to make sure invisible enemies don't fire so much
                        ActorGetGun(actor)->lock = 40;
                    }
                    if (cmd && !IsDirectionOK(actor, CmdToDirection(cmd)) &&
                            (actor->flags & FLAGS_DETOURING) == 0)
                    {
                        Detour(actor);
                        cmd = 0;
                        ActorSetAIState(actor, AI_STATE_TRACK);
                    }
                }
            }
        }
        actor->aiContext->Delay =
            MAX(0, actor->aiContext->Delay - ticks);
        CommandActor(actor, cmd, ticks);
    }
    else if ((actor->flags & FLAGS_PRISONER) != 0)
    {
        CommandActor(actor, 0, ticks);
    }
    CA_FOREACH_END()
    if (gMission.missionData->Enemies.size > 0 &&
            gMission.missionData->EnemyDensity > 0 &&
            count < MAX(1, (gMission.missionData->EnemyDensity * ConfigGetInt(&gConfig, "Game.EnemyDensity")) / 100))
    {
        NActorAdd aa = NActorAdd_init_default;
        aa.UID = ActorsGetNextUID();
        aa.CharId = CharacterStoreGetRandomBaddieId(
                        &gCampaign.Setting.characters);
        aa.Direction = rand() % DIRECTION_COUNT;
        const Character *c =
            CArrayGet(&gCampaign.Setting.characters.OtherChars, aa.CharId);
        aa.Health = CharacterGetStartingHealth(c, true);
        aa.FullPos = PlaceAwayFromPlayers(&gMap);
        GameEvent e = GameEventNew(GAME_EVENT_ACTOR_ADD);
        e.u.ActorAdd = aa;
        GameEventsEnqueue(&gGameEvents, e);
        gBaddieCount++;
    }
}
Пример #2
0
void CommandBadGuys(int ticks)
{
	int count = 0;
	int delayModifier;
	int rollLimit;

	switch (gConfig.Game.Difficulty)
	{
	case DIFFICULTY_VERYEASY:
		delayModifier = 4;
		rollLimit = 300;
		break;
	case DIFFICULTY_EASY:
		delayModifier = 2;
		rollLimit = 200;
		break;
	case DIFFICULTY_HARD:
		delayModifier = 1;
		rollLimit = 75;
		break;
	case DIFFICULTY_VERYHARD:
		delayModifier = 1;
		rollLimit = 50;
		break;
	default:
		delayModifier = 1;
		rollLimit = 100;
		break;
	}

	for (int i = 0; i < (int)gActors.size; i++)
	{
		TActor *actor = CArrayGet(&gActors, i);
		if (!actor->isInUse)
		{
			continue;
		}
		const CharBot *bot = actor->character->bot;
		if (!(actor->pData || (actor->flags & FLAGS_PRISONER)))
		{
			if ((actor->flags & (FLAGS_VICTIM | FLAGS_GOOD_GUY)) != 0)
			{
				gAreGoodGuysPresent = 1;
			}

			count++;
			int cmd = 0;

			// Wake up if it can see a player
			if ((actor->flags & FLAGS_SLEEPING) &&
				actor->aiContext->Delay == 0)
			{
				if (CanSeeAPlayer(actor))
				{
					actor->flags &= ~FLAGS_SLEEPING;
					actor->aiContext->State = AI_STATE_NONE;
				}
				actor->aiContext->Delay = bot->actionDelay * delayModifier;
				// Randomly change direction
				int newDir = (int)actor->direction + ((rand() % 2) * 2 - 1);
				if (newDir < (int)DIRECTION_UP)
				{
					newDir = (int)DIRECTION_UPLEFT;
				}
				if (newDir == (int)DIRECTION_COUNT)
				{
					newDir = (int)DIRECTION_UP;
				}
				cmd = DirectionToCmd((int)newDir);
			}
			// Go to sleep if the player's too far away
			if (!(actor->flags & FLAGS_SLEEPING) &&
				actor->aiContext->Delay == 0 &&
				!(actor->flags & FLAGS_AWAKEALWAYS))
			{
				if (!IsCloseToPlayer(actor->Pos, (40 * 16) << 8))
				{
					actor->flags |= FLAGS_SLEEPING;
					actor->aiContext->State = AI_STATE_IDLE;
				}
			}

			if (!actor->dead && !(actor->flags & FLAGS_SLEEPING))
			{
				bool bypass = false;
				const int roll = rand() % rollLimit;
				if (actor->flags & FLAGS_FOLLOWER)
				{
					if (IsCloseToPlayer(actor->Pos, 32 << 8))
					{
						cmd = 0;
						actor->aiContext->State = AI_STATE_IDLE;
					}
					else
					{
						cmd = AIGoto(
							actor, AIGetClosestPlayerPos(actor->Pos), true);
						actor->aiContext->State = AI_STATE_FOLLOW;
					}
				}
				else if (!!(actor->flags & FLAGS_SNEAKY) &&
					!!(actor->flags & FLAGS_VISIBLE) &&
					DidPlayerShoot())
				{
					cmd = AIHuntClosest(actor) | CMD_BUTTON1;
					if (actor->flags & FLAGS_RUNS_AWAY)
					{
						// Turn back and shoot for running away characters
						cmd = AIReverseDirection(cmd);
					}
					bypass = 1;
					actor->aiContext->State = AI_STATE_HUNT;
				}
				else if (actor->flags & FLAGS_DETOURING)
				{
					cmd = BrightWalk(actor, roll);
					actor->aiContext->State = AI_STATE_TRACK;
				}
				else if (actor->aiContext->Delay > 0)
				{
					cmd = actor->lastCmd & ~CMD_BUTTON1;
				}
				else
				{
					if (roll < bot->probabilityToTrack)
					{
						cmd = AIHuntClosest(actor);
						actor->aiContext->State = AI_STATE_HUNT;
					}
					else if (roll < bot->probabilityToMove)
					{
						cmd = DirectionToCmd(rand() & 7);
						actor->aiContext->State = AI_STATE_TRACK;
					}
					else
					{
						cmd = 0;
					}
					actor->aiContext->Delay = bot->actionDelay * delayModifier;
				}
				if (!bypass)
				{
					if (WillFire(actor, roll))
					{
						cmd |= CMD_BUTTON1;
						if (!!(actor->flags & FLAGS_FOLLOWER) &&
							(actor->flags & FLAGS_GOOD_GUY))
						{
							// Shoot in a random direction away
							for (int j = 0; j < 10; j++)
							{
								direction_e d =
									(direction_e)(rand() % DIRECTION_COUNT);
								if (!IsFacingPlayer(actor, d))
								{
									cmd = DirectionToCmd(d) | CMD_BUTTON1;
									break;
								}
							}
						}
						if (actor->flags & FLAGS_RUNS_AWAY)
						{
							// Turn back and shoot for running away characters
							cmd |= AIReverseDirection(AIHuntClosest(actor));
						}
						actor->aiContext->State = AI_STATE_HUNT;
					}
					else
					{
						if ((actor->flags & FLAGS_VISIBLE) == 0)
						{
							// I think this is some hack to make sure invisible enemies don't fire so much
							actor->weapon.lock = 40;
						}
						if (cmd && !IsDirectionOK(actor, CmdToDirection(cmd)) &&
							(actor->flags & FLAGS_DETOURING) == 0)
						{
							Detour(actor);
							cmd = 0;
							actor->aiContext->State = AI_STATE_TRACK;
						}
					}
				}
			}
			actor->aiContext->Delay =
				MAX(0, actor->aiContext->Delay - ticks);
			CommandActor(actor, cmd, ticks);
		}
		else if ((actor->flags & FLAGS_PRISONER) != 0)
		{
			CommandActor(actor, 0, ticks);
		}
	}
	if (gMission.missionData->Enemies.size > 0 &&
		gMission.missionData->EnemyDensity > 0 &&
		count < MAX(1, (gMission.missionData->EnemyDensity * gConfig.Game.EnemyDensity) / 100))
	{
		Character *character = CharacterStoreGetRandomBaddie(
			&gCampaign.Setting.characters);
		TActor *baddie = CArrayGet(&gActors, ActorAdd(character, NULL));
		PlaceBaddie(baddie);
		gBaddieCount++;
	}
}