static int BrightWalk(TActor * actor, int roll) { const CharBot *bot = ActorGetCharacter(actor)->bot; if (!!(actor->flags & FLAGS_VISIBLE) && roll < bot->probabilityToTrack) { actor->flags &= ~FLAGS_DETOURING; return AIHuntClosest(actor); } if (actor->flags & FLAGS_TRYRIGHT) { if (IsDirectionOK(actor, (actor->direction + 7) % 8)) { actor->direction = (actor->direction + 7) % 8; actor->turns--; if (actor->turns == 0) { actor->flags &= ~FLAGS_DETOURING; } } else if (!IsDirectionOK(actor, actor->direction)) { actor->direction = (actor->direction + 1) % 8; actor->turns++; if (actor->turns == 4) { actor->flags &= ~(FLAGS_DETOURING | FLAGS_TRYRIGHT); actor->turns = 0; } } } else { if (IsDirectionOK(actor, (actor->direction + 1) % 8)) { actor->direction = (actor->direction + 1) % 8; actor->turns--; if (actor->turns == 0) actor->flags &= ~FLAGS_DETOURING; } else if (!IsDirectionOK(actor, actor->direction)) { actor->direction = (actor->direction + 7) % 8; actor->turns++; if (actor->turns == 4) { actor->flags &= ~(FLAGS_DETOURING | FLAGS_TRYRIGHT); actor->turns = 0; } } } return DirectionToCmd(actor->direction); }
static int WillFire(TActor * actor, int roll) { const CharBot *bot = ActorGetCharacter(actor)->bot; if ((actor->flags & FLAGS_VISIBLE) != 0 && ActorCanFire(actor) && roll < bot->probabilityToShoot) { if ((actor->flags & FLAGS_GOOD_GUY) != 0) return 1; //!FacingPlayer( actor); else if (gAreGoodGuysPresent) { return 1; } else { return IsFacingPlayer(actor, actor->direction); } } return 0; }
static void DrawHealth( GraphicsDevice *device, const TActor *actor, const Vec2i pos, const FontAlign hAlign, const FontAlign vAlign) { char s[50]; Vec2i gaugePos = Vec2iAdd(pos, Vec2iNew(-1, -1)); Vec2i size = Vec2iNew(GAUGE_WIDTH, FontH() + 2); HSV hsv = { 0.0, 1.0, 1.0 }; color_t barColor; int health = actor->health; const int maxHealth = ActorGetCharacter(actor)->maxHealth; int innerWidth; color_t backColor = { 50, 0, 0, 255 }; innerWidth = MAX(1, size.x * health / maxHealth); if (actor->poisoned) { hsv.h = 120.0; hsv.v = 0.5; } else { double maxHealthHue = 50.0; double minHealthHue = 0.0; hsv.h = ((maxHealthHue - minHealthHue) * health / maxHealth + minHealthHue); } barColor = ColorTint(colorWhite, hsv); DrawGauge( device, gaugePos, size, innerWidth, barColor, backColor, hAlign, vAlign); sprintf(s, "%d", health); FontOpts opts = FontOptsNew(); opts.HAlign = hAlign; opts.VAlign = vAlign; opts.Area = gGraphicsDevice.cachedConfig.Res; opts.Pad = pos; FontStrOpt(s, Vec2iZero(), opts); }
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++; } }