|
Re: Уроки скриптологии
7. Описание обработчиков состояний НПС.
Все имена функций состояний должны начинаться с ZS_. Каждый процесс обработки соответствующего состояния состоит из 3х функций: ZS_xxx, ZS_xxx-Loop, ZS_xxx_End, где ххх - имя соответствующего состояния. Этим функциям соответствуют 3 фазы одного состояния НПС. 1 фаза - Begin: инициализация состояния НПС. 2 фаза - Loop: цикл выполнения последовательности действий НПС. Функция 2 фазы должна возвращать или LOOP_CONTINUE - продолжение фазы или LOOP_END - конец фазы. 3 фаза - End: завершение состояния НПС.
Системная функция AI_StartState может управлять последовательностью выполнения фаз состояний, за это отвечает параметр stateBehaviour, если он = 0, то выполняются все фазы состояния последовательно, если он = 1, то выполняется только заключительная фаза 3. Эта функция подробно описана в соответствующей теме.
8. Функции состояний людей.
Все файлы состояний людей расположены в директории ..AI\Human\ZS_Human
// ****************************** // Состояние атаки // ******************************
// Функция обработки вспомогательного восприятия PERC_ASSESSSURPRISE // Вызывается ядром системы когда ГГ превращается в человека из животного func void B_AssessSurprise() { * *// self - наблюдатель, other - ГГ * *// целью наблюдателя становится ГГ * *Npc_SetTarget(self,other); * *// причина нападения наблюдателя на ГГ - ГГ враг гильдии * *self.aivar[AIV_ATTACKREASON] = AR_GuildEnemy; };
// Функция инициализации состояния атаки func void ZS_Attack() { * *// установить минимальный набор восприятий НПС * *Perception_Set_Minimal(); * *// установить дополнительное восприятие на превращение * *Npc_PercEnable(self,PERC_ASSESSSURPRISE,B_AssessS urprise); * *// инициализировать переменную other (последняя цель) * *B_ValidateOther(); * *// записать НПС id последней цели * *self.aivar[AIV_LASTTARGET] = Hlp_GetInstanceID(other); * *// если НПС должен убегать от цели * *if(C_WantToFlee(self,other)) * * * * * * * * * * * *{ * * * *// очистка очереди AI состояний НПС * * * *Npc_ClearAIQueue(self); * * * *// очистка восприятий НПС * * * *B_ClearPerceptions(self); * * * *// установка цели для НПС * * * *Npc_SetTarget(self,other); * * * *// НПС убегает от цели * * * *AI_StartState(self,ZS_Flee,0,""); * * * *return; * *}; * *// если загрузки игры во время атаки не было * *if(self.aivar[AIV_LOADGAME] == FALSE) * *{ * * * *// НПС называет причину атаки * * * *B_Say_AttackReason(); * *}; * *// если режим сражения у НПС выключен * *if(Npc_IsInFightMode(self,FMODE_NONE)) * *{ * * * *// НПС достает лучшее оружие дальнего радиуса поражения * * * *AI_EquipBestRangedWeapon(self); * * * *// НПС достает лучшее оружие ближнего радиуса поражения * * * *AI_EquipBestMeleeWeapon(self); * *}; * *// НПС встает * *AI_StandUp(self); * *// перестает смотреть на других * *B_StopLookAt(self); * *// поворачивается к цели * *B_TurnToNpc(self,other); * *// бежит к цели * *AI_SetWalkmode(self,NPC_RUN); * *// сброс статуса предупреждений охраной * *self.aivar[AIV_Guardpassage_Status] = GP_NONE; * *// получить репутацию ГГ для конкретной локации * *self.aivar[AIV_LastAbsolutionLevel] = B_GetCurrentAbsolutionLevel(self); * *// сброс флага окончания преследования * *self.aivar[AIV_PursuitEnd] = FALSE; * *// сброс времени нахождения в состоянии * *self.aivar[AIV_StateTime] = 0; * *// сброс переменной вызова охраны (переменная AIV_TAPOSITION переопределена в этом состоянии) * *self.aivar[AIV_TAPOSITION] = 0; * *// сброс флага первого удара * *self.aivar[AIV_HitByOtherNpc] = 0; * *// сброс выбранного заклинания * *self.aivar[AIV_SelectSpell] = 0; };
// Функция цикла атаки func int ZS_Attack_Loop() { * *// Грег идет к Декстеру * *B_Greg_ComesToDexter(); * *// повторно инициализировать other целью * *Npc_GetTarget(self); * *// если расстояние между НПС и целью > дистанции прекращения сражения * *if(Npc_GetDistToNpc(self,other) > self.aivar[AIV_FightDistCancel]) * *{ * * * *// очистка очереди AI состояний НПС * * * *Npc_ClearAIQueue(self); * * * *// НПС встает * * * *AI_StandUp(self); * * * *// НПС закончил преследование * * * *self.aivar[AIV_PursuitEnd] = TRUE; * * * *return LOOP_END; * *}; * *// если время преследования превышает допустимое и НПС преследует * *if(Npc_GetStateTime(self) > self.aivar[AIV_MM_FollowTime]) && (self.aivar[AIV_PursuitEnd] == FALSE) * *{ * * * *Npc_ClearAIQueue(self); * * * *AI_StandUp(self); * * * *// НПС закончил преследование * * * *self.aivar[AIV_PursuitEnd] = TRUE; * * * *// получить дистанцию до цели * * * *self.aivar[AIV_Dist] = Npc_GetDistToNpc(self,other); * * * *// обновить время состояния НПС * * * *self.aivar[AIV_StateTime] = Npc_GetStateTime(self); * * * *// если цель человек * * * *if(other.guild < GIL_SEPERATOR_HUM) * * * *{ * * * * * *// НПС говорит цели "Беги, трус!" (SVM фраза) * * * * * *B_Say(self,other,"$RUNCOWARD"); * * * *}; * *}; * *// если НПС завершил преследование цели * *if(self.aivar[AIV_PursuitEnd] == TRUE) * *{ * * * *// если расстояние между НПС и целью > диапазона чувствительности НПС * * * *if(Npc_GetDistToNpc(self,other) > (self.senses_range)) * * * *{ * * * * * *return LOOP_END; * * * *}; * * * *// если текущее время > предыдущего времени (прошла как минимум секунда) * * * *if(Npc_GetStateTime(self) > self.aivar[AIV_StateTime]) * * * *{ * * * * * *// если расстояние между НПС и целью меньше дистанции, когда НПС прекратил преследование * * * * * *if(Npc_GetDistToNpc(self,other) < self.aivar[AIV_Dist]) * * * * * *// или (цель не бежит и не прыгает) * * * * * *¦¦ ((!C_BodyStateContains(other,BS_RUN)) && (!C_BodyStateContains(other,BS_JUMP))) * * * * * *{ * * * * * * * *// сброс флага окончания преследования * * * * * * * *self.aivar[AIV_PursuitEnd] = FALSE; * * * * * * * *// сброс времени нахождения НПС в этом состоянии * * * * * * * *Npc_SetStateTime(self,0); * * * * * * * *// сброс времени нахождения в состоянии * * * * * * * *self.aivar[AIV_StateTime] = 0; * * * * * *} * * * * * *else * * * * * *{ * * * * * * * *// НПС поворачивается к цели * * * * * * * *B_TurnToNpc(self,other); * * * * * * * *// получить дистанцию до цели * * * * * * * *self.aivar[AIV_Dist] = Npc_GetDistToNpc(self,other); * * * * * * * *// обновить время состояния НПС * * * * * * * *self.aivar[AIV_StateTime] = Npc_GetStateTime(self); * * * * * *}; * * * *}; * * * *return LOOP_CONTINUE; * *}; * *// если уровень достигнутый ГГ в сражении > первоначального уровня * *if(B_GetCurrentAbsolutionLevel(self) > self.aivar[AIV_LastAbsolutionLevel]) * *{ * * * *// очистка очереди AI состояний НПС * * * *Npc_ClearAIQueue(self); * * * *// НПС встает * * * *AI_StandUp(self); * * * *// прекращение атаки * * * *return LOOP_END; * *}; * *// если (цель плывет или ныряет) и НПС не преследует цель в воде * *if(C_BodyStateContains(other,BS_SWIM) ¦¦ C_BodyStateContains(other,BS_DIVE)) && (self.aivar[AIV_MM_FollowInWater] == FALSE) * *{ * * * *Npc_ClearAIQueue(self); * * * *AI_StandUp(self); * * * *// НПС закончил преследование * * * *self.aivar[AIV_PursuitEnd] = TRUE; * * * *return LOOP_END; * *}; * *// если НПС выжидает перед атакой * *if(self.aivar[AIV_WaitBeforeAttack] >= 1) * *{ * * * *// ожидание 0.8 сек * * * *AI_Wait(self,0.8 ); * * * *// сброс флага задержки * * * *self.aivar[AIV_WaitBeforeAttack] = 0; * *}; * *// если дистанция атаки > 0 * *if(self.aivar[AIV_MaxDistToWp] > 0) * *{ * * * *// если расстояние между НПС и вайпоинтом НПС > дистанции атаки и расстояние между целью и вайпоинтом НПС > дистанции акаки * * * *if(Npc_GetDistToWP(self,self.wp) > self.aivar[AIV_MaxDistToWp]) && (Npc_GetDistToWP(other,self.wp) > self.aivar[AIV_MaxDistToWp]) * * * *{ * * * * * *// установить НПС тактику защитников крепостных стен * * * * * *self.fight_tactic = FAI_NAILED; * * * *} * * * *else // иначе (если НПС или цель близка к вайпоинту НПС) * * * *{ * * * * * *// установить НПС родную тактику сражения * * * * * *self.fight_tactic = self.aivar[AIV_OriginalFightTactic]; * * * *}; * *}; * *// если цель не бежит и не прыгает * *if((!C_BodyStateContains(other,BS_RUN)) && (!C_BodyStateContains(other,BS_JUMP))) * *{ * * * *// сброс времени текущего состояния * * * *Npc_SetStateTime(self,0); * *}; * *// если время в состоянии > 2 сек (от последнего сброса) и охрана не вызывалась * *if(Npc_GetStateTime(self) > 2) && (self.aivar[AIV_TAPOSITION] == 0) * *{ * * * *// вызов охраны * * * *B_CallGuards(); * * * *// установка следующей фазы вызова охраны * * * *self.aivar[AIV_TAPOSITION] = 1; * *}; * *// если время в состоянии > 8 сек и охрана вызывалась * *if(Npc_GetStateTime(self) > 8 ) && (self.aivar[AIV_TAPOSITION] == 1) * *{ * * * *// вызов охраны * * * *B_CallGuards(); * * * *// установка следующей фазы вызова охраны (было 2 вызова) * * * *self.aivar[AIV_TAPOSITION] = 2; * *}; * *// подготовка НПС боезапаса * *B_CreateAmmo(self); * *// выбор соответствующего цели оружия * *B_SelectWeapon(self,other); * *// если цель существует и не обездвижена * *if((Hlp_IsValidNpc(other)) && (C_NpcIsDown(other) == FALSE)) * *{ * * * *// если цель не в состоянии разговора * * * *if(other.aivar[AIV_INVINCIBLE] == FALSE) * * * *{ * * * * * *// НПС атакует цель (Примечание: функция AI_Attack работает только когда очередь AI состояний НПС пуста) * * * * * *AI_Attack(self); * * * *} * * * *else * * * *{ * * * * * *// очистка очереди AI состояний НПС * * * * * *Npc_ClearAIQueue(self); * * * *}; * * * *// запись НПС id последней цели * * * *self.aivar[AIV_LASTTARGET] = Hlp_GetInstanceID(other); * * * *return LOOP_CONTINUE; * *} * *else // иначе (если цель отсутствует или обездвижена) * *{ * * * *// очистка очереди AI состояний НПС * * * *Npc_ClearAIQueue(self); * * * *// если цель существует и цель ГГ и ГГ обездвижен * * * *if(Hlp_IsValidNpc(other)) && (Npc_IsPlayer(other)) && (C_NpcIsDown(other)) * * * *{ * * * * * *// замена временного отношения НПС к ГГ на постоянное * * * * * *Npc_SetTempAttitude(self,Npc_GetPermAttitude(self ,hero)); * * * *}; * * * *// если причина атаки НПС не убийство цели * * * *if(self.aivar[AIV_ATTACKREASON] != AR_KILL) * * * *{ * * * * * *// НПС разрешено воспринимать все объекты * * * * * *Npc_PerceiveAll(self); * * * * * *// НПС ищет новую цель other * * * * * *Npc_GetNextTarget(self); * * * *}; * * * *// если цель существует и она не обездвижена * * * *if(Hlp_IsValidNpc(other)) && (!C_NpcIsDown(other)) * * * *// и (расстояние от НПС до цели < дистанции восприятия или цель ГГ) * * * *&& ((Npc_GetDistToNpc(self,other) < PERC_DIST_INTERMEDIAT) ¦¦ (Npc_IsPlayer(other))) * * * *// и расстояние между НПС и целью по высоте < дистанции восприятия по высоте * * * *&& (Npc_GetHeightToNpc(self,other) < PERC_DIST_HEIGHT) * * * *// и цель не в разговоре * * * *&& (other.aivar[AIV_INVINCIBLE] == FALSE) * * * *// и цель ГГ не является переодетым бандитом и НПС бандит * * * *&& (!(C_PlayerIsFakeBandit(self,other) && (self.guild == GIL_BDT))) * * * *{ * * * * * *// если гильдии НПС и цели враждебны * * * * * *if(Wld_GetGuildAttitude(self.guild,other.guild) == ATT_HOSTILE) * * * * * *{ * * * * * * * *// причина атаки - враждебная гильдия * * * * * * * *self.aivar[AIV_ATTACKREASON] = AR_GuildEnemy; * * * * * * * *// если цель ГГ * * * * * * * *if(Npc_IsPlayer(other)) * * * * * * * *{ * * * * * * * * * *// установить причину последнего нападения на ГГ * * * * * * * * * *self.aivar[AIV_LastPlayerAR] = AR_GuildEnemy; * * * * * * * * * *// параметр последнего сражения с ГГ - прервано * * * * * * * * * *self.aivar[AIV_LastFightAgainstPlayer] = FIGHT_CANCEL; * * * * * * * * * *// сброс комментария сражения * * * * * * * * * *self.aivar[AIV_LastFightComment] = FALSE; * * * * * * * *}; * * * * * *} * * * * * *// иначе, если сам НПС является врагом цели * * * * * *else if(Npc_GetAttitude(self,other) == ATT_HOSTILE) * * * * * *{ * * * * * * * *// причина атаки = причину последнего нападения на ГГ * * * * * * * *self.aivar[AIV_ATTACKREASON] = self.aivar[AIV_LastPlayerAR]; * * * * * *}; * * * * * *return LOOP_CONTINUE; * * * *} * * * *else * * * *{ * * * * * *// очистка очереди AI состояний НПС * * * * * *Npc_ClearAIQueue(self); * * * * * *// если последнее сражение с ГГ прервано и последняя цель не ГГ * * * * * *if(self.aivar[AIV_LastFightAgainstPlayer] == FIGHT_CANCEL) && (self.aivar[AIV_LASTTARGET] != Hlp_GetInstanceID(hero)) * * * * * *{ * * * * * * * *// комментировать сражение не нужно * * * * * * * *self.aivar[AIV_LastFightComment] = TRUE; * * * * * *}; * * * * * *return LOOP_END; * * * *}; * *}; };
//Функция завершения состояния атаки func void ZS_Attack_End() { * *// установить other на последнюю цель * *other = Hlp_GetNpc(self.aivar[AIV_LASTTARGET]); * *// усли преследование было прекращено * *if(self.aivar[AIV_PursuitEnd] == TRUE) * *{ * * * * * * *// если цель существует и цель ГГ и НПС не друг цели * * * *if(Hlp_IsValidNpc(other)) && (Npc_IsPlayer(other)) && (self.npctype != NPCTYPE_FRIEND) * * * *{ * * * * * *// установить временное отношение НПС к ГГ на враждебное * * * * * *Npc_SetTempAttitude(self,ATT_HOSTILE); * * * *}; * * * *// если НПС сражался на арене (состояние - в процессе сражения) * * * *if(self.aivar[AIV_ArenaFight] == AF_RUNNING) * * * *{ * * * * * *// установить состояние после сражения * * * * * *self.aivar[AIV_ArenaFight] = AF_AFTER; * * * *}; * *}; * *// если преследования не было * *if(self.aivar[AIV_PursuitEnd] == FALSE) * *{ * * * *// если уровень достигнутый ГГ в сражении > первоначального уровня * * * *if(B_GetCurrentAbsolutionLevel(self) > self.aivar[AIV_LastAbsolutionLevel]) * * * *{ * * * * * *// НПС говорит цели "Умный малый!" (SVM фраза) * * * * * *B_Say(self,other,"$WISEMOVE"); * * * *} * * * *else * * * *{ * * * * * *// обычная фраза завершения атаки * * * * * *B_Say_AttackEnd(); * * * *}; * *}; * *// если цель убита ГГ и отношения гильдий НПС и ГГ не враждебные * *if(other.aivar[AIV_KilledByPlayer] == TRUE) && (Wld_GetGuildAttitude(self.guild,hero.guild) != ATT_HOSTILE) * *{ * * * *// НПС становится другом ГГ * * * *B_SetAttitude(self,ATT_FRIENDLY); * *}; * *// если цель находится безсознания и причиной атаки было убийство цели * *if(Npc_IsInState(other,ZS_Unconscious)) && (C_NpcHasAttackReasonToKill(self)) * *{ * * * *// НПС добивает цель * * * *B_FinishingMove(self,other); * *}; * *// НПС прячет оружие * *AI_RemoveWeapon(self); * *// если цель обездвижена и НПС может обыскать цель и (цель не обыскивалась или должна быть обыскана) * *if(C_NpcIsDown(other)) && (C_WantToRansack(self)) && ((other.aivar[AIV_RANSACKED] == FALSE) ¦¦ C_NpcRansacksAlways(self)) * *// и расстояние между НПС и целью < дистанции восприятия * *&& (Npc_GetDistToNpc(self,other) < PERC_DIST_INTERMEDIAT) * *{ * * * *// установка флага, что цель обыскана * * * *other.aivar[AIV_RANSACKED] = TRUE; * * * *// цель человек * * * *if(other.guild < GIL_SEPERATOR_HUM) * * * *{ * * * * * *// переход НПС в состояние грабежа цели * * * * * *AI_StartState(self,ZS_RansackBody,0,""); * * * * * *return; * * * *} * * * *else // (не человек) * * * *{ * * * * * *// если НПС "Аллигатор Джек" и цель имеет "Сырое мясо" * * * * * *if(Hlp_GetInstanceID(self) == Hlp_GetInstanceID(AlligatorJack)) && (Npc_HasItems(other,ItFoMuttonRaw) > 0) * * * * * *{ * * * * * * * * *// Джек ест мясо * * * * * * * *AI_StartState(self,ZS_GetMeat,0,""); * * * * * * * *return; * * * * * *}; * * * *}; * *}; * *// если жизнь НПС меньше половинной * *if(self.attribute[ATR_HITPOINTS] < (self.attribute[ATR_HITPOINTS_MAX]/2)) * *{ * * * *// НПС лечит себя * * * *AI_StartState(self,ZS_HealSelf,0,""); * * * *return; * *}; };
|