include library.ai_lib; include library.chat; include library.buff; include library.utils; include library.combat; include library.groundquests; include library.factions; include library.smuggler; const string STRING_FILE = "smuggler/enemy"; const int FLAG_CLEAN_UP = 1; const int FLAG_ATTACK = 2; const int FLAG_FOLLOW = 3; const string VOL_PATROL_WATCH = "smugglerPatrolWatch"; const float VOL_PATROL_RANGE = 12.0f; trigger OnAttach() { messageTo(self, "startContrabandCheck", null, 2.0f, false); return SCRIPT_CONTINUE; } void doSnare(obj_id playerSmuggler, obj_id npc) { if (isIncapacitated(npc)) { return; } if (isIncapacitated(playerSmuggler)) { return; } if (utils.hasScriptVar(npc, "fastTalked")) { return; } int taunt = rand(1,5); if (taunt == 1) { string_id barkString = new string_id(STRING_FILE, "bark_snare"); chat.chat(npc, barkString); } buff.applyBuff(playerSmuggler, "caltropSnare"); return; } void broadcastCondition(obj_id playerSmuggler, obj_id npc, int flag) { location here = getLocation(npc); obj_id[] objects = getObjectsInRange(here, 32); for(int i = 0; i < objects.length; i++) if (hasObjVar(objects[i], "quest.owner")) { if ( (getObjIdObjVar(objects[i], "quest.owner") == playerSmuggler) && (npc != objects[i]) ) { switch (flag) { case FLAG_CLEAN_UP: messageTo(objects[i], "handleCleanUp", null, 1.0f, false); break; case FLAG_ATTACK: if (isIncapacitated(playerSmuggler)) { break; } if(!ai_lib.isInCombat(objects[i])) { if (!utils.hasScriptVar(objects[i], "fastTalked")) { startCombat(objects[i], playerSmuggler); } } else { obj_id enemyTarget = getHateTarget(objects[i]); if(!isIdValid(enemyTarget)) { break; } if (enemyTarget != playerSmuggler) { if (!utils.hasScriptVar(objects[i], "fastTalked")) { float hate = getMaxHate(objects[i]); addHate(objects[i], playerSmuggler, (hate+1000f)); } } } messageTo(objects[i], "combatLoop", null, 11.0f, false); break; case FLAG_FOLLOW: ai_lib.aiFollow( objects[i], npc, 3f, 6f ); messageTo(objects[i], "handleCleanUp", null, 9.0f, false); break; default: break; } } } return; } void enemyPickFight(obj_id npc, obj_id victimNpc, obj_id playerSmuggler) { clearHateList(npc); clearHateList(victimNpc); utils.setScriptVar(npc, "fastTalked", playerSmuggler); setMaster(npc, playerSmuggler); utils.setScriptVar(victimNpc, "fastTalked", playerSmuggler); startCombat(npc, victimNpc); startCombat(victimNpc, npc); addHate(npc, victimNpc, 9999.0f); addHate(victimNpc, npc, 9999.0f); string_id barkString = new string_id(STRING_FILE, "bark_myfriend"); chat.chat(npc, barkString); barkString = new string_id(STRING_FILE, "bark_huh"); chat.chat(victimNpc, barkString); dictionary params = new dictionary(); params.put("playerSmuggler", playerSmuggler); messageTo(npc, "endConfusion", params, 15.0f, false); messageTo(victimNpc, "endConfusion", params, 15.0f, false); return; } void doConfuse(obj_id playerSmuggler, obj_id npc) { removeHateTarget(npc, playerSmuggler); stopCombat(npc); string_id barkString = new string_id(STRING_FILE, "bark_confused"); chat.chat(npc, barkString); utils.setScriptVar(npc, "fastTalked", playerSmuggler); ai_lib.aiStopFollowing (npc); ai_lib.pathAwayFrom(npc, playerSmuggler); dictionary params = new dictionary(); params.put("playerSmuggler", playerSmuggler); messageTo(npc, "endConfusion", params, 15.0f, false); return; } void doConfuseAttack(obj_id playerSmuggler, obj_id npc) { location here = getLocation(npc); obj_id[] objects = getObjectsInRange(here, 25); obj_id victimEnemy = null; obj_id enemyTarget = null; for(int i = 0; i < objects.length; i++) { if (hasScript(objects[i], "ai.smuggler_spawn_enemy")) { if (objects[i] != npc) { victimEnemy = objects[i]; if(ai_lib.isInCombat(objects[i])) { enemyTarget = getHateTarget(objects[i]); if(isIdValid(enemyTarget)) { if (enemyTarget == playerSmuggler) { enemyPickFight(npc, objects[i],playerSmuggler); return; } } } } } } if(isIdValid(victimEnemy)) { enemyPickFight(npc, victimEnemy, playerSmuggler); } else { doConfuse(playerSmuggler, npc); } return; } trigger OnTriggerVolumeEntered( string volumeName, obj_id breacher ) { if (hasObjVar(breacher, "gm")) { return SCRIPT_CONTINUE; } if (ai_lib.isInCombat(self)) { return SCRIPT_CONTINUE; } if ( breacher == self ) { return SCRIPT_CONTINUE; } if ( isIncapacitated(self) ) { return SCRIPT_CONTINUE; } if ( isIncapacitated(breacher) ) { return SCRIPT_CONTINUE; } if ( volumeName == VOL_PATROL_WATCH ) { if(utils.getPlayerProfession(breacher) == utils.SMUGGLER) { if (groundquests.isDoingSmugglerMission(breacher)) { int taunt = rand(1,10); if (taunt == 1) { string_id barkString = new string_id(STRING_FILE, "bark_smuggler"); chat.chat(self, barkString); int smugglerLevel = combat.getLevel(breacher); int myLevel = combat.getLevel(self); if (smugglerLevel > myLevel) { int levelDifference = (smugglerLevel - myLevel); if (levelDifference > 5) { barkString = new string_id(STRING_FILE, "bark_help"); chat.chat(self, barkString); groundquests.sendSignal(breacher, "smugglerPatrolHelp"); } } } doSnare(breacher, self); startCombat(self, breacher); } } } return SCRIPT_CONTINUE; } messageHandler combatLoop() { if (isIncapacitated(self)) { return SCRIPT_CONTINUE; } if (utils.hasScriptVar(self, "fastTalked")) { return SCRIPT_CONTINUE; } if (hasObjVar(self, "quest.owner")) { obj_id playerSmuggler = (getObjIdObjVar(self, "quest.owner")); if(!isIdValid(playerSmuggler)) { return SCRIPT_CONTINUE; } if (isIncapacitated(playerSmuggler)) { messageTo(self, "handleCleanUp", null, 1.0f, false); } float distanceRange = getLocation(self).distance(getLocation(playerSmuggler)); if (distanceRange > 256.0f) { // Gonna Bail here - smuggler got away messageTo(self, "handleCleanUp", null, 1.0f, false); return SCRIPT_CONTINUE; } if(!ai_lib.isInCombat(self)) { if (!utils.hasScriptVar(self, "fastTalked")) { startCombat(self, playerSmuggler); } } if (!buff.hasBuff(playerSmuggler, "caltropSnare")) { doSnare(playerSmuggler, self); } messageTo(self, "combatLoop", null, 11.0f, false); } return SCRIPT_CONTINUE; } messageHandler smugglerKilled() { if (isIncapacitated(self)) { return SCRIPT_CONTINUE; } string_id barkString = new string_id(STRING_FILE, "bark_smack_talk"); chat.chat(self, barkString); if (hasObjVar(self, "quest.owner")) { obj_id playerSmuggler = (getObjIdObjVar(self, "quest.owner")); if(!isIdValid(playerSmuggler)) { return SCRIPT_CONTINUE; } messageTo(self, "handleCleanUp", null, 3.0f, false); broadcastCondition(playerSmuggler, self, FLAG_CLEAN_UP); } return SCRIPT_CONTINUE; } messageHandler startContrabandCheck() { if (isIncapacitated(self)) { return SCRIPT_CONTINUE; } if (hasObjVar(self, "quest.owner")) { setBaseWalkSpeed(self, 6.0f); setBaseRunSpeed(self, 9.0f); setAILeashTime(self, 999999); obj_id playerSmuggler = (getObjIdObjVar(self, "quest.owner")); // Pick a random number for string to bark int randStr = rand(1, 3); string_id barkString = new string_id(STRING_FILE, "bark_s" + randStr); // If I'm not in combat if(!ai_lib.isInCombat(self)) { faceTo(self, playerSmuggler); chat.chat(self, barkString); ai_lib.aiFollow( self, playerSmuggler, 3f, 6f ); } if (hasObjVar(self, "quest.count")) { int boss = getIntObjVar(self, "quest.count"); if (boss == 0) { if(!ai_lib.isInCombat(self)) { messageTo(self, "contrabandCheckResult", null, 11.0f, false); utils.setScriptVar(self, "contrabandCheck", 1); } else { broadcastCondition(playerSmuggler, self, FLAG_ATTACK); } } } } else // This is not a mission spawned enemy - patrolers need a trigger volume to agro { createTriggerVolume(VOL_PATROL_WATCH, VOL_PATROL_RANGE, true); } return SCRIPT_CONTINUE; } messageHandler contrabandCheckResult() { utils.removeScriptVar(self, "contrabandCheck"); if (isIncapacitated(self)) { return SCRIPT_CONTINUE; } if (hasObjVar(self, "quest.owner")) { obj_id playerSmuggler = (getObjIdObjVar(self, "quest.owner")); if(!isIdValid(playerSmuggler)) { return SCRIPT_CONTINUE; } int expertiseIncrease = 0; int rankIncrease = 0; if (utils.hasScriptVar(self, "slyLie")) { float underworldFaction = factions.getFactionStanding( playerSmuggler, "underworld" ); int smugglerRank = smuggler.getSmugglerRank(underworldFaction); expertiseIncrease = 10 + (int)getSkillStatisticModifier(playerSmuggler, "expertise_sly_lie_bonus"); rankIncrease = (int)getSkillStatisticModifier(self, "expertise_sly_lie_rank") * smugglerRank; utils.removeScriptVar(self, "slyLie"); } int finalChance = expertiseIncrease + rankIncrease; // Smuggler has a 5% base chance that mission enemies will not find contraband // Expertise and rank can modify this chance by 45% // The max chance to avoid an encounter using sly lie is 50% if (rand(1,100) > (finalChance + 5)) { string_id barkString = new string_id(STRING_FILE, "bark_attack"); if (finalChance > 0 ) { barkString = new string_id(STRING_FILE, "bark_lies_failed"); } // Start Attacking chat.chat(self, barkString); doSnare(playerSmuggler, self); if(!ai_lib.isInCombat(self)) { startCombat(self, playerSmuggler); } else { obj_id enemyTarget = getHateTarget(self); if(!isIdValid(enemyTarget)) { return SCRIPT_CONTINUE; } if (enemyTarget != playerSmuggler) { float hate = getMaxHate(self); addHate(self, playerSmuggler, (hate+1000f)); } } messageTo(self, "combatLoop", null, 11.0f, false); if (!hasObjVar(self, "bossEnemy")) { broadcastCondition(playerSmuggler, self, FLAG_ATTACK); } } else { if(!ai_lib.isInCombat(self)) { string_id barkString = new string_id(STRING_FILE, "bark_sorry"); chat.chat(self, barkString); ai_lib.pathAwayFrom(self, playerSmuggler); messageTo(self, "handleCleanUp", null, 9.0f, false); if (!hasObjVar(self, "bossEnemy")) { broadcastCondition(playerSmuggler, self, FLAG_FOLLOW); } } else { if (!hasObjVar(self, "bossEnemy")) { obj_id enemyTarget = getHateTarget(self); if (enemyTarget != playerSmuggler) { float hate = getMaxHate(self); addHate(self, playerSmuggler, (hate+1000f)); } broadcastCondition(playerSmuggler, self, FLAG_ATTACK); } } } } utils.removeScriptVar(self, "slyLie"); return SCRIPT_CONTINUE; } messageHandler fastTalkReaction() { obj_id playerSmuggler = params.getObjId("playerSmuggler"); if(!isIdValid(playerSmuggler)) { return SCRIPT_CONTINUE; } float underworldFaction = factions.getFactionStanding( playerSmuggler, "underworld" ); int smugglerRank = smuggler.getSmugglerRank(underworldFaction); int expertiseIncrease = (int)getSkillStatisticModifier(playerSmuggler, "expertise_fast_talk_bonus"); int rankIncrease = (int)getSkillStatisticModifier(self, "expertise_fast_talk_rank") * smugglerRank; int finalChance = expertiseIncrease + rankIncrease; // 75% max chance with expertise // 25% min chance int roll = rand(1,100); if (roll > (finalChance +25) ) { // Failed roll string_id barkString = new string_id(STRING_FILE, "bark_fast_talk_failed"); chat.chat(self, barkString); return SCRIPT_CONTINUE; } // Requires min bonus of 11 from expertise to trigger enemies to attack each other // At the max 40% chance for enemies to fight each other // At the min 1% chance for enemies to attack each other if (roll < (finalChance - 10) ) { doConfuseAttack(playerSmuggler, self); return SCRIPT_CONTINUE; } // I am confused doConfuse(playerSmuggler, self); return SCRIPT_CONTINUE; } messageHandler endConfusion() { obj_id playerSmuggler = params.getObjId("playerSmuggler"); setMaster(self, null); utils.removeScriptVar(self, "fastTalked"); if(!isIdValid(playerSmuggler)) { return SCRIPT_CONTINUE; } if ( (rand(1,5)) == 1) { string_id barkString = new string_id(STRING_FILE, "bark_notfooled"); chat.chat(self, barkString); } if(!ai_lib.isInCombat(self)) { startCombat(self, playerSmuggler); } else { obj_id enemyTarget = getHateTarget(self); if (enemyTarget != playerSmuggler) { float hate = getMaxHate(self); addHate(self, playerSmuggler, (hate+1000f)); } } messageTo(self, "combatLoop", null, 1.0f, false); return SCRIPT_CONTINUE; } messageHandler handleCleanUp() { destroyObject(self); return SCRIPT_CONTINUE; } trigger OnEnteredCombat() { // Strange the Ais want to keep fighting the smuggler - so we will grant them immunity till the 15 seconds pass if (utils.hasScriptVar(self, "fastTalked")) { obj_id noAttack = utils.getObjIdScriptVar(self, "fastTalked"); if(!isIdValid(noAttack)) { return SCRIPT_CONTINUE; } string_id barkString = new string_id(STRING_FILE, "bark_confused"); chat.chat(self, barkString); removeHateTarget(self, noAttack); ai_lib.aiStopFollowing (self); ai_lib.pathAwayFrom(self, noAttack); } return SCRIPT_CONTINUE; }