/*////////////////////////////////////////////////////////////////////////////// Script: nw_ch_ac1 Programmer: Philos //////////////////////////////////////////////////////////////////////////////// Associate(Summons, Familiar, Companion) OnHeart beat script when out of combat; This will usually fire every 6 seconds (1 game round). */////////////////////////////////////////////////////////////////////////////// #include "0i_module" #include "0i_menus" void ai_ActionFollow(object oCreature, object oTarget) { if(GetLocalInt(OBJECT_SELF, AI_CURRENT_ACTION_MODE) == AI_LAST_ACTION_MOVE) { float fDistance = GetDistanceBetween(oCreature, oTarget); float fFollowDistance = ai_GetFollowDistance(oCreature); if(fDistance > fFollowDistance) { if(fDistance > fFollowDistance * 5.0 && ai_GetIsInCombat(oCreature)) AssignCommand(oCreature, JumpToObject(oTarget)); else { ClearAllActions(); ActionMoveToObject(oTarget, TRUE, fFollowDistance); } } DelayCommand(1.0, ai_ActionFollow(oCreature, oTarget)); } } void main() { if (GetAILevel(OBJECT_SELF) == AI_LEVEL_VERY_LOW) return; object oCreature = OBJECT_SELF; if(AI_DEBUG) ai_Counter_Start(); // We run our OnSpawn in the heartbeat so the creator can use the original // OnSpawn for their own use. ai_OnAssociateSpawn(oCreature); if(AI_DEBUG) ai_Counter_End(GetName(oCreature) + ": Heartbeat, ai_OnAssociateSpawn"); if(AI_DEBUG) ai_Debug("nw_ch_ac1", "37", GetName(oCreature) + " Heartbeat." + " MODE_FOLLOW: " + IntToString(ai_GetAIMode(oCreature, AI_MODE_FOLLOW)) + " Action: " + IntToString(GetCurrentAction(oCreature))); if(ai_GetIsBusy(oCreature) || ai_Disabled(oCreature)) return; if(AI_DEBUG) ai_Counter_End(GetName(oCreature) + ": Heartbeat, ai_GetIsBusy/ai_Disabled"); // If we are an associate and don't have a master then exit. object oMaster = GetMaster(oCreature); if(AI_DEBUG) ai_Debug("nw_ch_ac1", "43", "oMaster: " + GetName(oMaster)); if(oMaster == OBJECT_INVALID) { if(ai_GetIsInCombat(oCreature)) { ai_DoAssociateCombatRound(oCreature); return; } ai_CheckForCombat(oCreature, FALSE); return; } // ***** Code for Henchman data and menus ***** if(ai_GetIsCharacter(oMaster)) { string sAssociateType = ai_GetAssociateType(oMaster, oCreature); ai_CheckAssociateData(oMaster, oCreature, sAssociateType); ai_CheckPCStart(oMaster); if(AI_HENCHMAN_WIDGET) { // This keeps widgets from disappearing and reappearing. int nUiToken = NuiFindWindow(oMaster, sAssociateType + AI_WIDGET_NUI); if(nUiToken) { json jData = NuiGetUserData(oMaster, nUiToken); object oAssociate = StringToObject(JsonGetString(JsonArrayGet(jData, 0))); if(oAssociate != oCreature) NuiDestroy(oMaster, nUiToken); } else { if(!ai_GetWidgetButton(oMaster, BTN_WIDGET_OFF, oCreature, sAssociateType)) { ai_CreateWidgetNUI(oMaster, oCreature); } } } if(AI_DEBUG) ai_Counter_End(GetName(oCreature) + ": Heartbeat, Get Associate data/Build widget"); } // If follow mode we do not want the NPC doing anything but follow. if(!ai_GetAIMode(oCreature, AI_MODE_FOLLOW)) { if(ai_GetAIMode(oCreature, AI_MODE_STAND_GROUND)) { ai_TryHealing(oCreature, oCreature); return; } if(ai_GetIsInCombat(oCreature)) { ai_DoAssociateCombatRound(oCreature); return; } if(ai_CheckForCombat(oCreature, FALSE)) return; if(AI_DEBUG) ai_Counter_End(GetName(oCreature) + ": Heartbeat, ai_CheckForCombat"); if(IsInConversation(oCreature)) return; // In command mode we let the player tell us what to do. if(!ai_GetAIMode(oCreature, AI_MODE_COMMANDED)) { if(ai_TryHealing(oCreature, oCreature)) return; if(AI_DEBUG) ai_Counter_End(GetName(oCreature) + ": Heartbeat: TryHealing"); if(ai_CheckNearbyObjects(oCreature)) return; if(AI_DEBUG) ai_Counter_End(GetName(oCreature) + ": Heartbeat: CheckNearbyObjects"); if(ai_GetAIMode(oCreature, AI_MODE_SCOUT_AHEAD)) { ai_ScoutAhead(oCreature); return; } } } // Finally we check to make sure we are following our master. if(GetCurrentAction(oCreature) != ACTION_FOLLOW) { //ai_Debug("nw_ch_ac1", "66", "Follow master: " + // " Stealth: " + IntToString(ai_GetAIMode(oCreature, AI_MODE_AGGRESSIVE_STEALTH)) + // " Search: " + IntToString(ai_GetAIMode(oCreature, AI_MODE_AGGRESSIVE_SEARCH))); if(ai_GetAIMode(oCreature, AI_MODE_AGGRESSIVE_STEALTH)) { if(AI_DEBUG) ai_Debug("nw_ch_ac1", "120", "Going into stealth mode!"); int nStealth = GetSkillRank(SKILL_HIDE, oCreature); nStealth += GetSkillRank(SKILL_MOVE_SILENTLY, oCreature); if(nStealth / 2 >= ai_GetCharacterLevels(oCreature)) { SetActionMode(oCreature, ACTION_MODE_STEALTH, TRUE); SetActionMode(oCreature, ACTION_MODE_DETECT, FALSE); } } else { SetActionMode(oCreature, ACTION_MODE_STEALTH, FALSE); if(ai_GetAIMode(oCreature, AI_MODE_AGGRESSIVE_SEARCH)) { if(AI_DEBUG) ai_Debug("nw_ch_ac1", "134", "Going into search mode!"); SetActionMode(oCreature, ACTION_MODE_DETECT, TRUE); } else SetActionMode(oCreature, ACTION_MODE_DETECT, FALSE); } // Follow master. if(GetDistanceBetween(oCreature, oMaster) > ai_GetFollowDistance(oCreature)) { if(!ai_GetAIMode(oCreature, AI_MODE_COMMANDED)) { object oTarget = GetLocalObject(oCreature, AI_FOLLOW_TARGET); if(oTarget == OBJECT_INVALID) oTarget = oMaster; //ActionForceFollowObject(oTarget, ai_GetFollowDistance(oCreature)); //ActionMoveToObject(oTarget, TRUE, ai_GetFollowDistance(oCreature)); SetLocalInt(oCreature, AI_CURRENT_ACTION_MODE, AI_LAST_ACTION_MOVE); ai_ActionFollow(oCreature, oTarget); } } } if(AI_DEBUG) ai_Counter_End(GetName(oCreature) + ": Heartbeat, end"); if(GetSpawnInCondition(NW_FLAG_HEARTBEAT_EVENT)) { SignalEvent(OBJECT_SELF, EventUserDefined(1001)); } }