/************************ [Include - Other AI Functions] *********************** Filename: j_inc_other_ai ************************* [Include - Other AI Functions] *********************** This contains fuctions and calls for these scripts: nw_c2_default2 - Percieve nw_c2_default3 - On Combat round End (For DetermineCombatRound() only) nw_c2_default4 - Conversation (shout) nw_c2_default5 - Phisical attacked nw_c2_default6 - Damaged nw_c2_default8 - Disturbed nw_c2_defaultb - Spell cast at Ones that don't use this use different/No includes. HOPEFULLY it will make them faster, if they don't run combat. They use Execute Script to initiate combat. (With the override ones initiating the override version, the normal initiateing the normal). ************************* [History] ******************************************** 1.3 - Added to speed up compilings and gather non-combat, or other workings in one place. ************************* [Workings] ******************************************* This is included, by #include "J_INC_OTHER_AI" in other AI files. They then use these functions in them scripts. ************************* [Arguments] ****************************************** Arguments: N/A ************************* Include - Other AI Functions] ***********************/ // All constants. #include "j_inc_constants" // Responds to it (like makinging the callers attacker thier target) // Called in OnConversation, and thats it. Use "ShouterFriend" To stop repeated GetIsFriend calls. void RespondToShout(object oShouter, int nShoutIndex); // Gets the attacker or attakee of the target, which should be a friend object GetIntruderFromShout(object oShouter); // Shouts, or really brings all people in 60.0M(by default) to the "shouter" void ShoutBossShout(object oEnemy); // Checks the target for a specific EFFECT_TYPE constant value // Returns TRUE or FALSE. Used On Damaged for polymorph checking. int GetHasEffect(int nEffectType, object oTarget = OBJECT_SELF); // This sets a morale penalty, to the exsisting one, if there is one. // It will reduce itself after fDuration (or if we die, ETC, it is deleted). // It is deleted at the end of combat as well. void SetMoralePenalty(int iPenalty, float fDuration = 0.0); // Removes iPenalty amount if it can. void RemoveMoralePenalty(int iPenalty); // At 5+ intelligence, we fire off any dispells at oPlaceables location void SearchDispells(object oPlaceable); // This MAY make us set a local timer to turn off hiding. // Turn of hiding, a timer to activate Hiding in the main file. This is // done in each of the events, with the opposition checking seen/heard. void TurnOffHiding(object oIntruder); // Used when we percieve a new enemy and are not in combat. Hides the creature // appropriatly with spawn settings and ability. // - At least it will clear all actions if it doesn't set hiding on void HideOrClear(); // This MIGHT move to oEnemy // - Checks special actions, such as fleeing, and may run instead! void ActionMoveToEnemy(object oEnemy); // Returns TRUE if we have under 0 morale, set to flee. // - They then run! (Badly) int PerceptionFleeFrom(object oEnemy); /*:://///////////////////////////////////////////// //:: Name: ShoutBossShout //:://///////////////////////////////////////////// This is used in the OnPercieve, and if we are set to, we will "shout" and bring lots of allies a running //:://///////////////////////////////////////////*/ void ShoutBossShout(object oEnemy) { if(GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_BOSS_MONSTER_SHOUT, AI_OTHER_COMBAT_MASTER)) { // Get the range (and default to 60.0 M) float fRange = IntToFloat(GetBoundriedAIInteger(AI_BOSS_MONSTER_SHOUT_RANGE, i60, 370)); // We loop through nearest not-seen, not-heard allies and get them // to attack the person. int Cnt = i1; // Not seen, not heard... object oAlly = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, OBJECT_SELF, Cnt, CREATURE_TYPE_IS_ALIVE, TRUE, CREATURE_TYPE_PERCEPTION, PERCEPTION_NOT_SEEN_AND_NOT_HEARD); // Get who thier target is. object oThierTarget; while(GetIsObjectValid(oAlly) && GetDistanceToObject(oAlly) <= fRange) { oThierTarget = GetLocalObject(oAlly, AI_TO_ATTACK); // If they are not attacking the enemy, we assing them to attack. if(oThierTarget != oEnemy) { // Can't be in combat. if(!GetIsInCombat(oAlly)) { // Set them to move to this SetLocalObject(oAlly, AI_TO_ATTACK, oEnemy); // Make them attack the person SetLocalObject(oAlly, AI_TEMP_SET_TARGET, oEnemy); ExecuteScript(COMBAT_FILE, oAlly); } } Cnt++; oAlly = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, OBJECT_SELF, Cnt, CREATURE_TYPE_IS_ALIVE, TRUE, CREATURE_TYPE_PERCEPTION, PERCEPTION_NOT_SEEN_AND_NOT_HEARD); } // Remove it :-) DeleteSpawnInCondition(AI_FLAG_OTHER_COMBAT_BOSS_MONSTER_SHOUT, AI_OTHER_COMBAT_MASTER); } } // This MAY make us set a local timer to turn off hiding. // Turn of hiding, a timer to activate Hiding in the main file. This is // done in each of the events, with the opposition checking seen/heard. void TurnOffHiding(object oIntruder) { if(!GetLocalTimer(AI_TIMER_TURN_OFF_HIDE) && // Are we actually seen/heard or is it just an AOE? (GetObjectSeen(OBJECT_SELF, oIntruder) || GetObjectHeard(OBJECT_SELF, oIntruder))) { SetLocalTimer(AI_TIMER_TURN_OFF_HIDE, f18); } } // Used when we percieve a new enemy and are not in combat. Hides the creature // appropriatly with spawn settings and ability. // - At least it will clear all actions if it doesn't set hiding on void HideOrClear() { // Spawn in conditions for it if(!GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_HIDING, AI_OTHER_COMBAT_MASTER) && GetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH) == FALSE) { // Need skill or force on if((GetSkillRank(SKILL_HIDE) - i4 >= GetHitDice(OBJECT_SELF)) || GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_HIDING, AI_OTHER_COMBAT_MASTER)) { // Use hide ClearAllActions(TRUE); SetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH, TRUE); // Stop return; } } // Else clear all actions normally. ClearAllActions(); } /*:://///////////////////////////////////////////// //:: Respond To Shouts //:: Copyright (c) 2001 Bioware Corp. //:://///////////////////////////////////////////// Useage: //NOTE ABOUT BLOCKERS int NW_GENERIC_SHOUT_BLOCKER = 2; It should be noted that the Generic Script for On Dialogue attempts to get a local set on the shouter by itself. This object represents the LastOpenedBy object. It is this object that becomes the oIntruder within this function. //NOTE ABOUT INTRUDERS These are the enemy that attacked the shouter. //NOTE ABOUT EVERYTHING ELSE I_WAS_ATTACKED = 1; If not in combat, attack the attackee of the shouter. Basically the best way to get people to come and help us. CALL_TO_ARMS = 3; If not in combat, determine combat round. By default, it should check any allies it can see/hear for thier targets and help them too. HELP_MY_FRIEND = 4; This is a runner thing. Said when the runner sees the target to run to. Gets a local location, and sets off people to run to it. If no valid area for the location, no moving :-P We also shout this if we are fleeing. It will set the person to buff too. LEADER_FLEE_NOW = 5 We flee to a pre-set object or follow the leader (who should be fleeing). LEADER_ATTACK_TARGET = 6 We attack the intruder next round, by setting it as a local object to override other choices. I_WAS_KILLED = 7 If lots are killed in one go - ouch! morale penalty each time someone dies. I_WAS_OPENED = 8 Chests/Doors which say this get the AI onto the tails of those who opened it, OR they get searched! :-) //:://///////////////////////////////////////////// // Modified almost completely: Jasperre //:://///////////////////////////////////////////*/ // Gets the attacker or attakee of the target, which should be a friend object GetIntruderFromShout(object oShouter) { object oIntruder = GetAttackTarget(oShouter); if(!GetIsObjectValid(oIntruder) || GetIgnoreNoFriend(oIntruder)) { oIntruder = GetLastHostileActor(oShouter); if(GetIgnoreNoFriend(oIntruder)) { return OBJECT_INVALID; } } return oIntruder; } void RespondToShout(object oShouter, int nShoutIndex) { object oIntruder; // Ones we don't care about if we are in combat... if(nShoutIndex == i6) // "Attack specific object" { // If a leader, we set it as a local object, nothing more if(GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_GROUP_LEADER, AI_OTHER_COMBAT_MASTER, oShouter)) { oIntruder = GetLocalObject(oShouter, AI_ATTACK_SPECIFIC_OBJECT); if(GetObjectSeen(oIntruder)) { // Set local object to use in next DetermineCombatRound. // We do not interrupt current acition (EG: Life saving stoneskins!) to re-direct. SetAIObject(AI_ATTACK_SPECIFIC_OBJECT, oIntruder); // 6 second delay. SetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID, f6); } } return; } else if(nShoutIndex == i5)// "leader flee now" { // If a leader, we set it as a local object, nothing more if(GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_GROUP_LEADER, AI_OTHER_COMBAT_MASTER, oShouter)) { oIntruder = GetLocalObject(oShouter, AI_FLEE_TO); // RUN! If intruder set is over 5.0M or no valid intruder ClearAllActions(); // 70. "[Shout] Reacting To Shout. [ShoutNo.] " + IntToString(iInput) + " [Shouter] " + GetName(oInput) DebugActionSpeakByInt(70, oShouter, nShoutIndex); SetCurrentAction(AI_SPECIAL_ACTIONS_FLEE); SetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID, f12); if(GetIsObjectValid(oIntruder)) { SetAIObject(AI_FLEE_TO, oIntruder); ActionMoveToObject(oIntruder); } else // Else, we will just follow our leader! { SetAIObject(AI_FLEE_TO, oShouter); ActionForceFollowObject(oShouter, f3); } } return; } // If the shout is number 8, it is "I was opened" and so can only be a // placeable or door. else if(nShoutIndex == i8)// "I was opened" { // We need somewhat complexe here - to get thier opener. int nType = GetObjectType(oShouter); // Check object type. If not a placeable nor door - stop script. if(nType == OBJECT_TYPE_PLACEABLE || nType == OBJECT_TYPE_DOOR) { // Now, we assign the placeable/door to set thier opener. // - Need to check it works. AssignCommand(oShouter, SetLocalObject(oShouter, PLACEABLE_LAST_OPENED_BY, GetLastOpenedBy())); oIntruder = GetLocalObject(oShouter, PLACEABLE_LAST_OPENED_BY); if(GetIsObjectValid(oIntruder)) { // Attack ClearAllActions(); DetermineCombatRound(oShouter); } } } // Else, we must not be in combat for the rest else if(!CannotPerformCombatRound()) { // Call to arms requires nothing special if(nShoutIndex == i3)// "Call to arms" { SetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID, f6); // 70. "[Shout] Reacting To Shout. [ShoutNo.] " + IntToString(iInput) + " [Shouter] " + GetName(oInput) DebugActionSpeakByInt(70, oShouter, nShoutIndex); DetermineCombatRound(); } // Ones we can GetIntruderFromShout(oShouter); if(nShoutIndex == i1 || // "I was attacked" nShoutIndex == i4 || // "Help my friend" nShoutIndex == i7) // "I was killed" { // Am not already fighting, and we don't ignore the intruder oIntruder = GetIntruderFromShout(oShouter); if(!GetIsObjectValid(oIntruder)) { return; } } if(nShoutIndex == i1 || nShoutIndex == i7) { // Morale penalty if they were killed if(nShoutIndex == i7) { SetMoralePenalty((GetHitDice(oShouter)/i4), f18); } // Get intruder // 70. "[Shout] Reacting To Shout. [ShoutNo.] " + IntToString(iInput) + " [Shouter] " + GetName(oInput) DebugActionSpeakByInt(70, oShouter, nShoutIndex); if(GetObjectSeen(oIntruder)) { // Stop, and attack, if we can see them! ClearAllActions(); SetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID, f9); DetermineCombatRound(oIntruder); DelayCommand(f2, AISpeakString(I_WAS_ATTACKED)); } else // Else the enemy is not seen { // If I can see neither the shouter nor the enemy // stop what I am doing, and move to the attacker. // - 1.3 change. They move to the attackers location (IE directed by ally) ClearAllActions(); SetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID, f6); // This will move to oIntruder if nothing else DetermineCombatRound(oIntruder); // Shout to other allies, after a second. DelayCommand(f2, AISpeakString(HELP_MY_FRIEND)); } } else if(nShoutIndex == i4)// "Help my friend" { // We move to where the runner/shouter wants us. location lMoveTo = GetLocalLocation(oShouter, AI_HELP_MY_FRIEND_LOCATION); // 70. "[Shout] Reacting To Shout. [ShoutNo.] " + IntToString(iInput) + " [Shouter] " + GetName(oInput) DebugActionSpeakByInt(70, oShouter, nShoutIndex); SetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID, f6); if(GetIsObjectValid(GetAreaFromLocation(lMoveTo))) { ActionMoveToLocation(lMoveTo, TRUE); ActionDoCommand(DetermineCombatRound()); } else { // If we do not know of the friend attacker, we will follow them ClearAllActions(); SetSpawnInCondition(AI_FLAG_COMBAT_FLAG_FAST_BUFF_ENEMY, AI_COMBAT_MASTER); ActionForceFollowObject(oShouter, f3); ActionDoCommand(DetermineCombatRound()); } } } } void SearchDispells(object oPlaceable) { // No dispelling at low intelligence. if(GetBoundriedAIInteger(AI_INTELLIGENCE) < i5) return; location lPlace = GetLocation(oPlaceable); // Move closer if not seen. if(!GetObjectSeen(oPlaceable)) { // Move nearer - 6 M is out of the dispell range ActionMoveToObject(oPlaceable, TRUE, f6); } // Dispell if we have any - at the location of oPlaceable. if(GetHasSpell(SPELL_LESSER_DISPEL)) { ActionCastSpellAtLocation(SPELL_LESSER_DISPEL, lPlace); } else if(GetHasSpell(SPELL_DISPEL_MAGIC)) { ActionCastSpellAtLocation(SPELL_DISPEL_MAGIC, lPlace); } else if(GetHasSpell(SPELL_GREATER_DISPELLING)) { ActionCastSpellAtLocation(SPELL_GREATER_DISPELLING, lPlace); } else if(GetHasSpell(SPELL_MORDENKAINENS_DISJUNCTION)) { ActionCastSpellAtLocation(SPELL_MORDENKAINENS_DISJUNCTION, lPlace); } } // Get Has Effect // Checks to see if the target has a given // effect, usually from a spell. Really useful this is. int GetHasEffect(int nEffectType, object oTarget = OBJECT_SELF) { effect eCheck = GetFirstEffect(oTarget); while(GetIsEffectValid(eCheck)) { if(GetEffectType(eCheck) == nEffectType) { return TRUE; break; } eCheck = GetNextEffect(oTarget); } return FALSE; } // This sets a morale penalty, to the exsisting one, if there is one. // It will reduce itself (by the penalty) after fDuration (or if we die, ETC, it is deleted). // It is deleted at the end of combat as well. void SetMoralePenalty(int iPenalty, float fDuration = 0.0) { int iOriginal = GetAIInteger(AI_MORALE_PENALTY); int iNew = iOriginal + iPenalty; SetAIInteger(AI_MORALE_PENALTY, iNew); DelayCommand(fDuration, RemoveMoralePenalty(iPenalty)); } void RemoveMoralePenalty(int iPenalty) { int iOriginal = GetAIInteger(AI_MORALE_PENALTY); int iNew = iOriginal - iPenalty; if(iNew > 0 && !GetIsDead(OBJECT_SELF)) { SetAIInteger(AI_MORALE_PENALTY, iNew); } else { DeleteAIInteger(AI_MORALE_PENALTY); } } // This MIGHT move to oEnemy // - Checks special actions, such as fleeing, and may run instead! void ActionMoveToEnemy(object oEnemy) { // Make sure that we are not fleeing badly (-1 morale from all enemies) if(GetIsEnemy(oEnemy)) { // -1 morale, flee if(PerceptionFleeFrom(oEnemy)) return; } if(GetIsPerformingSpecialAction()) { // Stop if we have an action we don't want to override return; } // End default is move to the enemy ClearAllActions(); ActionMoveToObject(oEnemy, TRUE); // combat round to heal/search/whatever if(!GetFactionEqual(oEnemy)) { ActionDoCommand(DetermineCombatRound(oEnemy)); } } // Returns TRUE if we have under 0 morale, set to flee. // - They then run! (Badly) int PerceptionFleeFrom(object oEnemy) { object oRunTarget = oEnemy; if(GetAIInteger(AI_INTELLIGENCE) < FALSE) { // Valid run from target if(!GetIsObjectValid(oRunTarget)) { oRunTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, i1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE); if(!GetIsObjectValid(oRunTarget)) { oRunTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, i1, CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD, CREATURE_TYPE_IS_ALIVE, TRUE); if(!GetIsObjectValid(oRunTarget)) { oRunTarget = GetLastHostileActor(); if(!GetIsObjectValid(oRunTarget) || GetIsDead(oRunTarget)) { // Stop - nothing to flee from! return FALSE; } } } } // Run from enemy ClearAllActions(); ActionMoveAwayFromObject(oRunTarget, TRUE, f50); return TRUE; } // 0 or more morale. return FALSE; } // Debug: To compile this script full, uncomment all of the below. /* - Add two "/"'s at the start of this line void main() { return; } //*/