package script.ai; import script.*; import script.library.*; public class ai extends script.base_script { public ai() { } //public static final boolean LOGGING_ON = false; public static final String LOGGING_CATEGORY = "ai_script"; public static final String MENU_FILE = "pet/pet_menu"; //public static final float CORPSE_CLEANUP_DELAY = 300.0f; public static final String CREATURE_TABLE = "datatables/mob/creatures.iff"; //public static final string_id SID_NOTIFY_STALKED = new string_id("skl_use", "notify_stalked"); public static final string_id SID_CANT_MILK = new string_id("skl_use", "milk_cant"); public static final string_id SID_MILK_NOT_HIDDEN = new string_id("skl_use", "milk_not_hidden"); public static final string_id SID_MILK_BEGIN = new string_id("skl_use", "milk_begin"); public static final string_id SID_MILK_TOO_FAR = new string_id("skl_use", "milk_too_far"); public static final string_id SID_CANT_MILK_THE_DEAD = new string_id("skl_use", "milk_cant_milk_the_dead"); public static final string_id SID_MILK_CONTINUE = new string_id("skl_use", "milk_continue"); public static final string_id SID_MILK_SUCCESS = new string_id("skl_use", "milk_success"); public static final string_id SID_BEING_MILKED = new string_id("skl_use", "being_milked"); public static final string_id SID_CANT_MILK_MOUNTED = new string_id("skl_use", "milk_mounted"); //public static final string_id SID_CANT_MILK_COMBAT = new string_id("skl_use", "milk_combat"); public static final string_id SID_CANT_MILK_INV_FULL = new string_id("skl_use", "milk_inventory_full"); public static final string_id SID_ALREADY_RECRUITED = new string_id("collection", "already_recruited"); public static final string_id SID_ENEMY_RECRUIT = new string_id("collection", "enemy_recruit"); public static final string_id SID_GAVE_RECRUIT_ITEM = new string_id("collection", "gave_recruit_item"); public static final string_id SID_NPC_MEATLUMP_SPEAK = new string_id("collection", "npc_meatlump_speak"); public static final string_id SID_NO_RECRUIT_REB_IMP = new string_id("collection", "no_recruit_reb_imp"); public void initializeScript() throws InterruptedException { obj_id self = getSelf(); LOGC(aiLoggingEnabled(self), "debug_ai", "ai::initializeScript() self(" + self + ":" + getName(self) + ")"); if (hasObjVar(self, "ai.threat")) { removeObjVar(self, "ai.threat"); } if (ai_lib.isAggro(self)) { setCondition(self, CONDITION_AGGRESSIVE); } location loc = getLocation(self); boolean setHomeLoc = true; if (loc == null) { setHomeLoc = false; LOG("debug_ai", "WARNING: got null location in ai.initializeScript for creature " + self); } else if (loc.area == null) { setHomeLoc = false; LOG("debug_ai", "WARNING: null scene from getLocation in ai.initializeScript for creature " + self); } else if (loc.area.length() == 0) { setHomeLoc = false; LOG("debug_ai", "WARNING: empty scene from getLocation in ai.initializeScript for creature " + self); } if (setHomeLoc) { aiSetHomeLocation(self, loc); } setWantSawAttackTriggers(self, aiIsAssist(self) || aiIsGuard(self)); if (!hasObjVar(self, "ai.defaultCalmBehavior")) { setObjVar(self, "ai.defaultCalmBehavior", ai_lib.BEHAVIOR_LOITER); } if (!hasObjVar(self, "ai.yaw")) { float ai_yaw = getYaw(self); setObjVar(self, "ai.yaw", ai_yaw); } ai_lib.resetAi(); } public int OnAttach(obj_id self) throws InterruptedException { LOGC(aiLoggingEnabled(self), "debug_ai", "ai::OnAttach() self(" + self + ":" + getName(self) + ")"); initializeScript(); return SCRIPT_CONTINUE; } public int OnAddedToWorld(obj_id self) throws InterruptedException { LOGC(aiLoggingEnabled(self), "debug_ai", "ai::OnAddedToWorld() self(" + self + ":" + getName(self) + ")"); messageTo(self, "handleOnAddedToWorldDelay", null, 2, false); return SCRIPT_CONTINUE; } public int handleOnAddedToWorldDelay(obj_id self, dictionary params) throws InterruptedException { LOGC(aiLoggingEnabled(self), "debug_ai", "ai::OnAddedToWorld() self(" + self + ":" + getName(self) + ")"); initializeScript(); return SCRIPT_CONTINUE; } public int OnRemovingFromWorld(obj_id self) throws InterruptedException { if (ai_lib.isAiDead(self) && !pet_lib.isPet(self) && !beast_lib.isBeast(self) && isObjectPersisted(self)) { destroyObject(self); } return SCRIPT_CONTINUE; } public int OnFleeTargetLost(obj_id self, obj_id oldTarget) throws InterruptedException { if (aiLoggingEnabled(self)) { debugSpeakMsg(self, "OnFleeTargetLost(" + oldTarget + ")"); } removeObjVar(self, "ai.threat"); doDefaultCalmBehavior(self); return SCRIPT_CONTINUE; } public int OnFleePathNotFound(obj_id self, obj_id oldTarget) throws InterruptedException { if (aiLoggingEnabled(self)) { debugSpeakMsg(self, "OnFleePathNotFound(" + oldTarget + ")"); } doDefaultCalmBehavior(self); return SCRIPT_CONTINUE; } public int OnFleeWaypoint(obj_id self, obj_id target) throws InterruptedException { return SCRIPT_CONTINUE; } public int resumeDefaultCalmBehavior(obj_id self, dictionary params) throws InterruptedException { if (isInNpcConversation(self) || aiIsTethered(self)) { if (!hasMessageTo(self, "resumeDefaultCalmBehavior")) { messageTo(self, "resumeDefaultCalmBehavior", null, 5, false); } return SCRIPT_CONTINUE; } LOGC(aiLoggingEnabled(self), "debug_ai", "ai::resumeDefaultCalmBehavior() self(" + self + getName(self) + ")"); doDefaultCalmBehavior(self); return SCRIPT_CONTINUE; } public void doDefaultCalmBehavior(obj_id npc) throws InterruptedException { if (!npc.isLoaded() || !exists(npc)) { LOGC(aiLoggingEnabled(npc), "debug_ai", "ai::doDefaultCalmBehavior() npc(?) ISN'T LOADED!"); return; } if (ai_lib.isInCombat(npc)) { LOGC(aiLoggingEnabled(npc), "debug_ai", "ai::doDefaultCalmBehavior() npc(" + npc + ") I THINK I AM IN COMBAT"); return; } if (ai_lib.isAiDead(npc)) { LOGC(aiLoggingEnabled(npc), "debug_ai", "ai::doDefaultCalmBehavior() npc(" + npc + ") I THINK I AM INCAPACITATED"); return; } removeObjVar(npc, "ai.threat"); ai_lib.setMood(npc, ai_lib.MOOD_CALM); messageTo(npc, "redoYaw", null, 30, false); if (ai_lib.isFollowing(npc)) { obj_id target = ai_lib.getFollowTarget(npc); LOGC(aiLoggingEnabled(npc), "debug_ai", "ai::doDefaultCalmBehavior() npc(" + npc + ") IS FOLLOWING " + target.toString()); if (isIdValid(target) && exists(target) && !ai_lib.isAiDead(target) && isInWorld(target)) { ai_lib.resumeFollow(npc); return; } removeObjVar(npc, "ai.persistantFollowing"); } if (hasObjVar(npc, "ai.inFormation")) { LOGC(aiLoggingEnabled(npc), "debug_ai", "ai::doDefaultCalmBehavior() npc(" + npc + ") IN FORMATION"); if (getPosture(npc) != POSTURE_UPRIGHT) { posture.stand(npc); } ai_lib.resumeFormationFollowing(npc); return; } if (ai_lib.canPatrol(npc)) { LOGC(aiLoggingEnabled(npc), "debug_ai", "ai::doDefaultCalmBehavior() npc(" + npc + ") PATROLING"); if (getPosture(npc) != POSTURE_UPRIGHT) { posture.stand(npc); } ai_lib.resumePatrol(npc); return; } if (hasObjVar(npc, "ai.persistentPathing")) { LOGC(aiLoggingEnabled(npc), "debug_ai", "ai::doDefaultCalmBehavior() npc(" + npc + ") PATHING"); if (getPosture(npc) != POSTURE_UPRIGHT) { posture.stand(npc); } location pathLoc = getLocationObjVar(npc, "ai.persistentPathing"); pathTo(npc, pathLoc); return; } if (hasObjVar(npc, "ai.persistentPathingWaypoint")) { LOGC(aiLoggingEnabled(npc), "debug_ai", "ai::doDefaultCalmBehavior() npc(" + npc + ") ai.persistentPathingWaypoint"); if (getPosture(npc) != POSTURE_UPRIGHT) { posture.stand(npc); } String pathWaypoint = getStringObjVar(npc, "ai.persistentPathingWaypoint"); pathTo(npc, pathWaypoint); return; } if (getConfigSetting("GameServer", "disableAILoitering") != null) { LOGC(aiLoggingEnabled(npc), "debug_ai", "ai::doDefaultCalmBehavior() npc(" + npc + ") disableAILoitering"); return; } final int defaultBehavior = ai_lib.getDefaultCalmBehavior(npc); switch (defaultBehavior) { case ai_lib.BEHAVIOR_STOP: case ai_lib.BEHAVIOR_SENTINEL: LOGC(aiLoggingEnabled(npc), "debug_ai", "ai::doDefaultCalmBehavior() npc(" + npc + getName(npc) + ") BEHAVIOR_STOP"); stop(npc); break; case ai_lib.BEHAVIOR_LOITER: case ai_lib.BEHAVIOR_WANDER: default: if (pet_lib.isPet(npc) || beast_lib.isBeast(npc)) { aiSetHomeLocation(npc, getLocation(npc)); } final float collisionRadius = getObjectCollisionRadius(npc); float minDistance; float maxDistance; if (hasObjVar(npc, "ai.loiterMinRange")) { minDistance = getFloatObjVar(npc, "ai.loiterMinRange"); maxDistance = getFloatObjVar(npc, "ai.loiterMaxRange"); } else { final float cellDistanceModifier = !isIdValid(getLocation(npc).cell) ? 3.0f : 1.0f; maxDistance = Math.min(128.0f, collisionRadius * 7.0f * cellDistanceModifier); minDistance = 0.0f; } final float minDelay = Math.min(Math.max(8.0f, collisionRadius * 2.0f), 16.0f); final float maxDelay = Math.min(Math.max(8.0f, collisionRadius * 4.0f), 16.0f); loiterLocation(npc, aiGetHomeLocation(npc), minDistance, maxDistance, minDelay, maxDelay); break; } } public int OnFollowMoving(obj_id self, obj_id target) throws InterruptedException { if (!ai_lib.isInCombat(self) && !ai_lib.isAiDead(self) && getPosture(self) != POSTURE_UPRIGHT) { stop(self); removeObjVar(self, "ai.combat.moveMode"); posture.stand(self); messageTo(self, "resumeDefaultCalmBehavior", null, 2, false); } return SCRIPT_CONTINUE; } public int OnFollowTargetLost(obj_id self, obj_id oldTarget) throws InterruptedException { LOGC(aiLoggingEnabled(self), "debug_ai", "ai::OnFollowTargetLost() self(" + self + ":" + getName(self) + ")"); if (!ai_lib.isInCombat(self)) { ai_lib.aiStopFollowing(self); } return SCRIPT_CONTINUE; } public int OnExitedCombat(obj_id self) throws InterruptedException { utils.removeScriptVar(self, "sentAllyDistressCall"); return SCRIPT_CONTINUE; } public int OnFollowWaiting(obj_id self, obj_id target) throws InterruptedException { /* if (!target.isLoaded() || !exists(target) || hasObjVar(target, "gm") || ai_lib.isInCombat(self)) { return SCRIPT_CONTINUE; } */ if (!isIdValid(target) || ai_lib.isAiDead(target)) { ai_lib.aiStopFollowing(self); } return SCRIPT_CONTINUE; } public int OnFollowPathNotFound(obj_id self, obj_id target) throws InterruptedException { LOGC(aiLoggingEnabled(self), "debug_ai", "ai::OnFollowPathNotFound() self(" + self + ":" + getName(self) + ")"); if (!ai_lib.isInCombat(self)) { ai_lib.aiStopFollowing(self); } return SCRIPT_CONTINUE; } public int OnMovePathComplete(obj_id self) throws InterruptedException { if (!isValidId(self) || !exists(self)) { return SCRIPT_CONTINUE; } LOGC(aiLoggingEnabled(self), "debug_ai", "ai::OnMovePathComplete() self(" + self + ")"); if (hasObjVar(self, "ai.persistentPathing")) { location pathLoc = getLocationObjVar(self, "ai.persistentPathing"); if (utils.getDistance(self, pathLoc) < 2.0f) { removeObjVar(self, "ai.persistentPathing"); } } if (hasObjVar(self, "ai.persistentWaypoint")) { removeObjVar(self, "ai.persistentPathingWaypoint"); } if (!ai_lib.isInCombat(self)) { if (getBehavior(self) <= BEHAVIOR_CALM) { ai_lib.resumePatrol(self); } if (utils.hasScriptVar(self, "pathingToAttack")) { obj_id target = utils.getObjIdScriptVar(self, "pathingToAttack"); if (isIdValid(target)) { startCombat(self, target); } utils.removeScriptVar(self, "pathingToAttack"); } } return SCRIPT_CONTINUE; } public int OnMovePathNotFound(obj_id self) throws InterruptedException { LOGC(aiLoggingEnabled(self), "debug_ai", "ai::OnMovePathNotFound() self(" + self + ":" + getName(self) + ")"); if (utils.hasScriptVar(self, "pathingToAttack")) { utils.removeScriptVar(self, "pathingToAttack"); } stop(self); if (getBehavior(self) <= BEHAVIOR_CALM && !ai_lib.isAiDead(self)) { setLocation(self, aiGetHomeLocation(self)); messageTo(self, "resumeDefaultCalmBehavior", null, 5, false); } return SCRIPT_CONTINUE; } public int OnTriggerVolumeEntered(obj_id self, String volumeName, obj_id breacher) throws InterruptedException { if (utils.hasScriptVar(self, "petBeingInitialized")) { LOGC(aiLoggingEnabled(self), "debug_ai", "ai::OnTriggerVolumeEntered(" + volumeName + ") self(" + self + ":" + getName(self) + ") PET BEING INITIALIZED"); return SCRIPT_CONTINUE; } if (!isMob(breacher)) { LOGC(aiLoggingEnabled(self), "debug_ai", "ai::OnTriggerVolumeEntered(" + volumeName + ") SCRIPT_CONTINUE - The breacher is not a mob"); return SCRIPT_CONTINUE; } if (breacher == self) { LOGC(aiLoggingEnabled(self), "debug_ai", "ai::OnTriggerVolumeEntered(" + volumeName + ") SCRIPT_CONTINUE - The breacher == self"); return SCRIPT_CONTINUE; } if (ai_lib.isAiDead(self)) { LOGC(aiLoggingEnabled(self), "debug_ai", "WARNING: ai::OnTriggerVolumeEntered(" + volumeName + ") self(" + self + ":" + getName(self) + ") I AM DEAD"); return SCRIPT_CONTINUE; } if (beast_lib.isBeast(self) && (!beast_lib.getBeastDefensive(self) || !hasCommand(getMaster(self), beast_lib.BM_COMMAND_ATTACK))) { return SCRIPT_CONTINUE; } LOGC(aiLoggingEnabled(self), "debug_ai", "ai::OnTriggerVolumeEntered(" + volumeName + ") self(" + self + ":" + getName(self) + ") radius(" + getTriggerVolumeRadius(self, volumeName) + ") breacher(" + breacher + ":" + getName(breacher) + ")"); final boolean breacherIsAPlayer = isPlayer(breacher); if (volumeName.equals(ai_lib.ALERT_VOLUME_NAME)) { if (breacherIsAPlayer && !ai_lib.isMonster(self)) { ai_lib.greet(self, breacher); } if (hasTriggerVolume(self, ai_lib.AGGRO_VOLUME_NAME)) { boolean aggro = false; if (pvpIsEnemy(self, breacher)) { LOGC(aiLoggingEnabled(self), "debug_ai", "ai::OnTriggerVolumeEntered(" + volumeName + ") Breacher is a threat (pvp enemy)"); aggro = true; } else { if (breacherIsAPlayer) { final int factionStatus = factions.getFactionStatus(self, breacher); if (factionStatus == factions.STATUS_ENEMY) { LOGC(aiLoggingEnabled(self), "debug_ai", "ai::OnTriggerVolumeEntered(" + volumeName + ") Player breacher is a threat (faction enemy)"); aggro = true; } else if ((factionStatus == factions.STATUS_NEUTRAL) && aiIsAggressive(self)) { LOGC(aiLoggingEnabled(self), "debug_ai", "ai::OnTriggerVolumeEntered(" + volumeName + ") Player breacher is a threat (faction neutral, I am aggressive)"); aggro = true; } else if (pvpGetAlignedFaction(self) != 0) { LOGC(aiLoggingEnabled(self), "debug_ai", "ai::OnTriggerVolumeEntered(" + volumeName + ") Player breacher is a NOT currently a threat (but could be with faction alignment change)"); aggro = true; } else { LOGC(aiLoggingEnabled(self), "debug_ai", "ai::OnTriggerVolumeEntered(" + volumeName + ") Player breacher is a NOT a threat"); } } else { if (aiIsGuard(self)) { final String breacherFaction = factions.getFaction(breacher); if ((breacherFaction != null) && (breacherFaction.equals("townsperson") || breacherFaction.equals("ImperialCitizen") || breacherFaction.equals("RebelCitizen"))) { LOGC(aiLoggingEnabled(self), "debug_ai", "ai::OnTriggerVolumeEntered(" + volumeName + ") guard: AI breacher is a NOT a threat (townsperson)"); } else { if (ai_lib.isSameSocialGroup(self, breacher)) { LOGC(aiLoggingEnabled(self), "debug_ai", "ai::OnTriggerVolumeEntered(" + volumeName + ") guard: AI breacher is NOT a threat (same social group)"); } else if (pet_lib.isPet(breacher) || beast_lib.isBeast(breacher)) { LOGC(aiLoggingEnabled(self), "debug_ai", "ai::OnTriggerVolumeEntered(" + volumeName + ") guard: AI breacher is NOT a threat (pet)"); } else { if (ai_lib.isAnimal(breacher)) { String creatureType = getStringObjVar(self, "creature_type"); if (creatureType.startsWith("gcw_city")) { LOGC(aiLoggingEnabled(self), "debug_ai", "ai::OnTriggerVolumeEntered(" + volumeName + ") guard: AI breacher is NOT a threat (gcw_city_invasion npc)"); } else { LOGC(aiLoggingEnabled(self), "debug_ai", "ai::OnTriggerVolumeEntered(" + volumeName + ") guard: AI breacher is a threat (animal)"); aggro = true; } } else if (factions.getFactionStatus(self, breacher) == factions.STATUS_ENEMY) { LOGC(aiLoggingEnabled(self), "debug_ai", "ai::OnTriggerVolumeEntered(" + volumeName + ") guard: AI breacher is a threat (factional enemy)"); aggro = true; } else if (hasAttributeAttained(breacher, attrib.THUG)) { LOGC(aiLoggingEnabled(self), "debug_ai", "ai::OnTriggerVolumeEntered(" + volumeName + ") guard: AI breacher is a threat (thug)"); aggro = true; } else { LOGC(aiLoggingEnabled(self), "debug_ai", "ai::OnTriggerVolumeEntered(" + volumeName + ") guard: AI breacher is NOT a threat"); } } } } else { if (ai_lib.isSameSocialGroup(self, breacher)) { LOGC(aiLoggingEnabled(self), "debug_ai", "ai::OnTriggerVolumeEntered(" + volumeName + ") AI breacher is NOT a threat (same social group)"); } else { final int factionStatus = factions.getFactionStatus(self, breacher); if (factionStatus == factions.STATUS_ENEMY) { LOGC(aiLoggingEnabled(self), "debug_ai", "ai::OnTriggerVolumeEntered(" + volumeName + ") AI breacher is a threat (factional enemy)"); aggro = true; } else { LOGC(aiLoggingEnabled(self), "debug_ai", "ai::OnTriggerVolumeEntered(" + volumeName + ") AI breacher is NOT a threat"); } } } } } if (hasObjVar(self, "storytellerid")) { if (!utils.hasScriptVar(breacher, "storytellerid")) { LOGC(aiLoggingEnabled(self), "debug_ai", "ai::OnTriggerVolumeEntered(" + volumeName + ") Player breacher is a NOT a member of my Story"); aggro = false; } else { if (getObjIdObjVar(self, "storytellerid") != utils.getObjIdScriptVar(breacher, "storytellerid")) { LOGC(aiLoggingEnabled(self), "debug_ai", "ai::OnTriggerVolumeEntered(" + volumeName + ") Player breacher is a NOT a member of my Story (but he is a member of another Story)"); aggro = false; } } } if (aggro) { addTriggerVolumeEventSource(ai_lib.AGGRO_VOLUME_NAME, breacher); } } } else if (volumeName.equals(ai_lib.AGGRO_VOLUME_NAME)) { if (!isPlayer(breacher)) { ai_aggro.requestAggroCheck(breacher); } else { if (!scout.isScentMasked(breacher, self)) { if (isIncapacitated(breacher)) { LOGC(aiLoggingEnabled(self), "debug_ai", "ai::requestSawRecapacitation() self(" + self + ":" + getName(self) + ") breacher(" + breacher + ":" + getName(breacher) + ") Listening for breacher recapacitation"); listenToMessage(breacher, "handleSawRecapacitation"); } ai_aggro.requestAggroCheck(breacher); } } } return SCRIPT_CONTINUE; } public int OnTriggerVolumeExited(obj_id self, String volumeName, obj_id breacher) throws InterruptedException { LOGC(aiLoggingEnabled(self), "debug_ai", "ai::OnTriggerVolumeExited(" + volumeName + ") self(" + self + ":" + getName(self) + ") radius(" + getTriggerVolumeRadius(self, volumeName) + ") breacher(" + breacher + ":" + getName(breacher) + ")"); if (utils.hasScriptVar(self, "petBeingInitialized")) { return SCRIPT_CONTINUE; } if (volumeName.equals(ai_lib.ALERT_VOLUME_NAME)) { if (isPlayer(breacher) && !ai_lib.isMonster(self)) { ai_lib.dismiss(self, breacher); } removeTriggerVolumeEventSource(ai_lib.AGGRO_VOLUME_NAME, breacher); if (hasScript(self, "systems.missions.dynamic.mission_bounty_target")) { obj_id objHunter = getObjIdObjVar(self, "objHunter"); if (!isIdValid(objHunter) || objHunter != breacher) { pvpRemovePersonalEnemyFlags(self, breacher); } } else { pvpRemovePersonalEnemyFlags(self, breacher); } } else if (volumeName.equals(ai_lib.AGGRO_VOLUME_NAME)) { if (isPlayer(breacher)) { LOGC(aiLoggingEnabled(self), "debug_ai", "ai::requestSawRecapacitation() self(" + self + ":" + getName(self) + ") breacher(" + breacher + ":" + getName(breacher) + ") Stop listening for breacher recapacitation"); stopListeningToMessage(breacher, "handleSawRecapacitation"); } } return SCRIPT_CONTINUE; } public int OnLoiterWaiting(obj_id self, modifiable_float time) throws InterruptedException { if (ai_lib.isHerdingCreature(self)) { ai_lib.doAction(self, "eat"); } return SCRIPT_CONTINUE; } public boolean isThreat(obj_id npc, obj_id breacher) throws InterruptedException { if (hasObjVar(breacher, "gm")) { LOGC(aiLoggingEnabled(npc), "debug_ai", "ai::isThreat() npc(" + npc + ") breacher(" + breacher + ") breacher is a gm"); return false; } if (!isValidId(breacher)) { LOGC(aiLoggingEnabled(npc), "debug_ai", "ai::isThreat() npc(" + npc + ") breacher(" + breacher + ") invalid breacher id"); return false; } if (!isMob(breacher)) { LOGC(aiLoggingEnabled(npc), "debug_ai", "ai::isThreat() npc(" + npc + ") breacher(" + breacher + ") breacher is not a mob"); return false; } if (ai_lib.isAiDead(npc)) { LOGC(aiLoggingEnabled(npc), "debug_ai", "ai::isThreat() npc(" + npc + ") breacher(" + breacher + ") npc is dead"); return false; } if (!isPlayer(breacher) && ai_lib.isAiDead(breacher)) { LOGC(aiLoggingEnabled(npc), "debug_ai", "ai::isThreat() npc(" + npc + ") breacher(" + breacher + ") breacher is dead ai"); return false; } if (isInvulnerable(npc)) { LOGC(aiLoggingEnabled(npc), "debug_ai", "ai::isThreat() npc(" + npc + ") breacher(" + breacher + ") npc is invulnerable"); return false; } if (isInvulnerable(breacher)) { LOGC(aiLoggingEnabled(npc), "debug_ai", "ai::isThreat() npc(" + npc + ") breacher(" + breacher + ") breacher is invulnerable"); return false; } if (!pvpCanAttack(npc, breacher)) { LOGC(aiLoggingEnabled(npc), "debug_ai", "ai::isThreat() !pvpCanAttack - npc(" + npc + ":" + getName(npc) + ") npcPvpType(" + pvpGetType(npc) + ") npcPvpAlignedFaction(" + pvpGetAlignedFaction(npc) + ") breacher(" + breacher + ":" + getName(breacher) + ") breacherPvpType(" + pvpGetType(breacher) + ") breacherPvpAlignedFaction(" + pvpGetAlignedFaction(breacher) + ")"); return false; } obj_id master = getMaster(breacher); if (isIdValid(master) && exists(master)) { LOGC(aiLoggingEnabled(npc), "debug_ai", "ai::isThreat() npc(" + npc + ") breacher(" + breacher + ") breacher is a pet/beast with a master"); return false; } return (ai_lib.isAggroToward(npc, breacher) || ai_lib.isAggroToward(breacher, npc)); } public void goAlert(obj_id npc) throws InterruptedException { if (ai_lib.isAiDead(npc)) { return; } if (ai_lib.isInCombat(npc)) { return; } if (!hasObjVar(npc, "ai.pathingAwayFrom")) { stop(npc); } ai_lib.doAction(npc, ai_lib.ACTION_ALERT); ai_lib.setMood(npc, ai_lib.MOOD_NERVOUS); obj_id threat = getObjIdObjVar(npc, "ai.threat"); if (isIdValid(threat)) { debugSpeakMsg(npc, "FEAR 7"); addToMentalStateToward(npc, threat, FEAR, -5.0f); } } public void goThreaten(obj_id npc) throws InterruptedException { if (ai_lib.isAiDead(npc)) { return; } if (ai_lib.isInCombat(npc)) { return; } obj_id threat = getObjIdObjVar(npc, "ai.threat"); if (!isIdValid(threat)) { return; } if (hasObjVar(threat, "gm")) { return; } stop(npc); faceTo(npc, threat); ai_lib.doThreatenAnimation(npc); debugSpeakMsg(npc, "FEAR 8"); addToMentalStateToward(npc, threat, FEAR, -5.0f); if (!isPlayer(threat)) { debugSpeakMsg(threat, "FEAR 9"); addToMentalStateToward(threat, npc, FEAR, 10.0f); } ai_lib.setMood(npc, ai_lib.MOOD_NERVOUS); } public int OnBehaviorChange(obj_id self, int newBehavior, int oldBehavior, int[] changeFlags) throws InterruptedException { return SCRIPT_CONTINUE; } public int handleSetDefaultBehavior(obj_id self, dictionary params) throws InterruptedException { doDefaultCalmBehavior(self); return SCRIPT_CONTINUE; } public int OnGetAttributes(obj_id self, obj_id player, String[] names, String[] attribs) throws InterruptedException { int idx = utils.getValidAttributeIndex(names); if (idx == -1) { blog("idx was negative 1"); return SCRIPT_CONTINUE; } String milkType = ai_lib.getMilkType(self); if (milkType != null && ai_lib.isMonster(self) && !beast_lib.isBeast(self)) { names[idx] = "got_milk"; string_id strIdMilkType = new string_id("resource/resource_names", milkType); attribs[idx] = utils.packStringId(strIdMilkType); idx++; } final String creatureName = getCreatureName(self); if (creatureName == null) { return SCRIPT_CONTINUE; } dictionary creatureKnowledge = beast_lib.getBeastMasterExamineInfo(player, self, names, attribs, idx); names = creatureKnowledge.getStringArray("names"); attribs = creatureKnowledge.getStringArray("attribs"); idx = creatureKnowledge.getInt("idx"); return SCRIPT_CONTINUE; } public int snareEffectOff(obj_id self, dictionary params) throws InterruptedException { showFlyText(self, new string_id("combat_effects", "no_snare"), 1.0f, colors.TOMATO); return SCRIPT_CONTINUE; } public int OnDefenderCombatAction(obj_id self, obj_id attacker, obj_id weapon, int combatResult) throws InterruptedException { if (ai_lib.isAiDead(self) || isInvulnerable(self)) { return SCRIPT_OVERRIDE; } if (combatResult == COMBAT_RESULT_HIT) { chat.setAngryMood(self); ai_lib.barkString(self, "hit"); } return SCRIPT_CONTINUE; } public int OnSawAttack(obj_id self, obj_id defender, obj_id[] attackers) throws InterruptedException { LOGC(aiLoggingEnabled(self), "debug_ai", "ai::OnSawAttack() self(" + self + ":" + getName(self) + ") defender (" + defender + ") attackers.length(" + attackers.length + ")"); if (beast_lib.isBeast(self)) { return SCRIPT_CONTINUE; } if (defendLair(self, defender, attackers, false)) { if (hasScript(self, "npc.converse.npc_convo")) { if (!isInNpcConversation(self) && !pet_lib.isPet(self) && !beast_lib.isBeast(self)) { detachScript(self, "npc.converse.npc_convo"); clearCondition(self, CONDITION_CONVERSABLE); } } debugSpeakMsgc(aiLoggingEnabled(self), self, "lair defense"); } else { if (pet_lib.isPet(self) && pet_lib.isGuarding(self, defender)) { for (final obj_id attacker : attackers) { if (isIdValid(attacker)) { startCombat(self, attacker); if (!ai_lib.isInCombat(self) && (defender == getMaster(self))) { ai_lib.barkString(self, "ally"); } } } } else if (aiIsGuard(self)) { boolean assistDefender = false; final String defenderFaction = factions.getFaction(defender); if (defenderFaction != null) { if (defenderFaction.equals("townsperson") || defenderFaction.equals("ImperialCitizen") || defenderFaction.equals("RebelCitizen")) { assistDefender = true; } } if (!assistDefender && ai_lib.isSameSocialGroup(self, defender)) { assistDefender = true; } for (final obj_id attacker : attackers) { if (isIdValid(attacker)) { if (assistDefender || hasAttributeAttained(attacker, attrib.THUG) || (ai_lib.isMonster(attacker) && (!pet_lib.isPet(attacker)))) { debugSpeakMsgc(aiLoggingEnabled(self), self, "OnSawAttackGuard() attacking(" + attacker + ")"); ai_combat_assist.assist(self, attacker); break; } else if (ai_lib.isSameSocialGroup(self, attacker)) { debugSpeakMsgc(aiLoggingEnabled(self), self, "OnSawAttack() attacking(" + defender + ")"); ai_combat_assist.assist(self, defender); break; } } } } else { for (final obj_id attacker : attackers) { if (isIdValid(attacker)) { if (hasObjVar(self, "storytellerid")) { if (!utils.hasScriptVar(defender, "storytellerid") && !utils.hasScriptVar(attacker, "storytellerid")) { debugSpeakMsgc(aiLoggingEnabled(self), self, "OnSawAttack() not attacking(" + defender + ") or (" + attacker + ") as they are not a part of my story"); break; } else if (hasObjVar(defender, "storytellerid") && utils.hasScriptVar(attacker, "storytellerid")) { if (getObjIdObjVar(self, "storytellerid") == getObjIdObjVar(defender, "storytellerid") && ai_lib.isSameSocialGroup(self, defender)) { debugSpeakMsgc(aiLoggingEnabled(self), self, "OnSawAttack() attacking(" + attacker + ")"); ai_combat_assist.assist(self, defender); break; } } else if (utils.hasScriptVar(defender, "storytellerid") && hasObjVar(attacker, "storytellerid")) { if (getObjIdObjVar(self, "storytellerid") == getObjIdObjVar(attacker, "storytellerid") && ai_lib.isSameSocialGroup(self, attacker)) { debugSpeakMsgc(aiLoggingEnabled(self), self, "OnSawAttack() attacking(" + defender + ")"); ai_combat_assist.assist(self, attacker); break; } } } if (ai_lib.isSameSocialGroup(self, defender)) { debugSpeakMsgc(aiLoggingEnabled(self), self, "OnSawAttack() attacking(" + attacker + ")"); ai_combat_assist.assist(self, attacker); break; } else if (ai_lib.isSameSocialGroup(self, attacker)) { debugSpeakMsgc(aiLoggingEnabled(self), self, "OnSawAttack() attacking(" + defender + ")"); ai_combat_assist.assist(self, defender); break; } } } } } return SCRIPT_CONTINUE; } public boolean defendLair(obj_id npc, obj_id defender, obj_id[] attackers, boolean isInCombat) throws InterruptedException { if (isMob(defender)) { return false; } if (utils.hasScriptVar(npc, "ai.noLair")) { return false; } obj_id myPOI = ai_lib.getLair(npc); if (!isIdValid(myPOI)) { return false; } if (!hasObjVar(defender, "poi.baseObject")) { return false; } if (getObjIdObjVar(defender, "poi.baseObject") == myPOI) { if (getHitpoints(defender) >= getMaxHitpoints(defender)) { return true; } if (pvpGetAlignedFaction(npc) == (221551254)) { factions.setFaction(npc, "angry"); } int endLoop = attackers.length; if (endLoop > 20) { endLoop = 20; } for (int i = 0; i < endLoop; i++) { if (isIdValid(attackers[i])) { if (!isInCombat) { startCombat(npc, attackers[i]); if (utils.hasScriptVar(npc, "pathingToAttack")) { utils.removeScriptVar(npc, "pathingToAttack"); } return true; } } } return true; } return false; } public int stopFleeing(obj_id self, dictionary params) throws InterruptedException { debugSpeakMsg(self, "stopping fleeing"); if (!ai_lib.isInCombat(self)) { if (getDistance(getLocation(self), aiGetHomeLocation(self)) > 40.0f) { pathTo(self, aiGetHomeLocation(self)); } } messageTo(self, "redoYaw", null, 30, false); if (getBehavior(self) <= BEHAVIOR_CALM) { messageTo(self, "resumeDefaultCalmBehavior", null, 5, false); } return SCRIPT_CONTINUE; } public int OnIncapacitated(obj_id self, obj_id attacker) throws InterruptedException { LOGC(aiLoggingEnabled(self), "debug_ai", ("ai::OnIncapacitated() self(" + self + ":" + getName(self) + ") attacker(" + attacker + ")")); debugSpeakMsgc(aiLoggingEnabled(self), self, "OnIncapacitated"); chat.setBadMood(self); ai_lib.barkString(self, "death"); if (!pet_lib.isPet(self) && !beast_lib.isBeast(self) && !utils.hasScriptVar(self, "petBeingInitialized")) { obj_id weapon = getCurrentWeapon(self); if (isIdValid(weapon) && !isDefaultWeapon(weapon)) { destroyObject(weapon); } obj_id cInv = utils.getInventoryContainer(self); if (isIdValid(cInv)) { utils.emptyContainerExceptStorytellerLoot(cInv); } ai_lib.clearCombatData(); setObjVar(self, xp.VAR_LANDED_DEATHBLOW, attacker); if (!kill(self)) { obj_id[] haters = getHateList(self); if (haters.length > 0) { for (obj_id hater : haters) { removeHateTarget(hater, self); } } destroyObject(self); } clearCondition(self, CONDITION_INTERESTING); } return SCRIPT_CONTINUE; } public int OnDeath(obj_id self, obj_id killer, obj_id corpseId) throws InterruptedException { if (isIdValid(killer) && exists(killer) && isIdValid(self) && exists(self)) { removeHateTarget(killer, self); } obj_id player = utils.getObjIdScriptVar(self, "ai.listeningTo"); if (!isValidId(player) || !exists(player)) { return SCRIPT_CONTINUE; } if (hasObjVar(self, gcw.GCW_ENTERTAINMENT_FLAG) && utils.hasScriptVar(self, gcw.GCW_SCRIPTVAR_PARENT + ".isGcwEntertained")) { LOG("gcw_entertainer", "NPC is saving time player stopped entertaining"); utils.setScriptVar(self, gcw.GCW_STOPPED_ENTERTAINING, getGameTime()); int pid = sui.getPid(player, gcw.ENTERTAIN_GCW_TROOPS_PID); if (pid > 0) { forceCloseSUIPage(pid); } if (hasObjVar(self, gcw.GCW_PATROL_OBJ)) { obj_id patrolObject = getObjIdObjVar(self, gcw.GCW_PATROL_OBJ); if (isValidId(patrolObject)) { dictionary webster = new dictionary(); webster.put("npc", self); webster.put("player", player); messageTo(patrolObject, "handleOffensiveEntertainedNpcCleanUp", webster, 1, false); } } } return SCRIPT_CONTINUE; } public int xpDelegated(obj_id self, dictionary params) throws InterruptedException { obj_id cInv = utils.getInventoryContainer(self); if (isIdValid(cInv)) { setOwner(cInv, obj_id.NULL_ID); } if (!beast_lib.isBeast(self)) { attachScript(self, corpse.SCRIPT_AI_CORPSE); messageTo(self, "aiCorpsePrepared", null, 0, false); } else { xp.cleanupCreditForKills(); } return SCRIPT_CONTINUE; } public int aiCorpsePrepared(obj_id self, dictionary params) throws InterruptedException { obj_id[] killers = getObjIdArrayObjVar(self, scenario.VAR_PRIMARY_KILLERS); obj_id[] pks = null; if (killers != null && killers.length > 0) { pks = xp.getPlayersFromKillerList(killers); } if (pks == null || pks.length <= 0) { return SCRIPT_CONTINUE; } boolean hasLoot = loot.addLoot(self); String goldenTicketActive = getConfigSetting("EventTeam", "goldenTicket"); if(goldenTicketActive != null && goldenTicketActive.equals("true")) { for (obj_id killer : killers) { loot.addGoldenTicket(killer, self); } } boolean hasChanceToDropChroniclesLoot = false; if (hasObjVar(self, xp.VAR_TOP_GROUP)) { obj_id killCredit = getObjIdObjVar(self, xp.VAR_TOP_GROUP); if (group.isGroupObject(killCredit)) { obj_id[] groupMembers = getGroupMemberIds(killCredit); for (obj_id groupMember : groupMembers) { if (isPlayer(groupMember) && !loot.hasToggledChroniclesLootOff(groupMember)) { hasChanceToDropChroniclesLoot = true; } } } else { if (!loot.hasToggledChroniclesLootOff(killCredit)) { hasChanceToDropChroniclesLoot = true; } } } if (hasChanceToDropChroniclesLoot) { hasLoot |= loot.addChronicleLoot(self); } if(scheduled_drop.isSystemEnabled()) { int corpseLevel = getLevel(self); boolean doNotDropCard = false; int difficultyClass = getIntObjVar(self, "difficultyClass"); int sourceSystem = scheduled_drop.SYSTEM_COMBAT_NORMAL; switch (difficultyClass) { case 0: sourceSystem = scheduled_drop.SYSTEM_COMBAT_NORMAL; break; case 1: sourceSystem = scheduled_drop.SYSTEM_COMBAT_ELITE; break; case 2: sourceSystem = scheduled_drop.SYSTEM_COMBAT_BOSS; break; } int delayCount = 0; for (obj_id pk1 : pks) { if (isIdValid(pk1) && (corpseLevel + 5 < getLevel(pk1) || utils.isFreeTrial(pk1))) { doNotDropCard = true; } if (isIdValid(pk1) && scheduled_drop.hasCardDelay(pk1, sourceSystem)) { delayCount++; } } if (delayCount > pks.length / 2) { doNotDropCard = true; } boolean canDrop = scheduled_drop.canDropCard(sourceSystem); for (obj_id pk : pks) { if (isIdValid(pk)) { utils.setScriptVar(pk, scheduled_drop.PLAYER_SCRIPTVAR_DROP_TIME, getGameTime()); if (isGod(pk) && hasObjVar(pk, "qa_tcg_always_drop")) { if (!doNotDropCard) { canDrop = true; } } if (isGod(pk) && hasObjVar(pk, "qa_tcg")) { sendSystemMessageTestingOnly(pk, "QA TCG COMBAT. Do not drop card? " + doNotDropCard + " hasCardDelay? " + scheduled_drop.hasCardDelay(pk, sourceSystem) + " isTrial? " + utils.isFreeTrial(pk) + " bad level? " + (corpseLevel + 5 < getLevel(pk))); } } } if (!doNotDropCard) { obj_id inv = utils.getInventoryContainer(self); if (isIdValid(inv) && canDrop) { scheduled_drop.dropCard(sourceSystem, inv); hasLoot = true; } } } if (hasLoot) { corpse.showLootMeParticle(self); } setObjVar(self, "readyToLoot", true); xp.cleanupCreditForKills(); return SCRIPT_CONTINUE; } public int corpseCleanup(obj_id self, dictionary params) throws InterruptedException { destroyObject(self); return SCRIPT_CONTINUE; } public int OnStartNpcConversation(obj_id self, obj_id speaker) throws InterruptedException { LOGC(aiLoggingEnabled(self), "debug_ai", ("ai::OnStartNpcConversation() self(" + self + ":" + getName(self) + ") speaker(" + speaker + ":" + getName(speaker) + ")")); if (!isInNpcConversation(self)) { return SCRIPT_CONTINUE; } if (ai_lib.isAiDead(self)) { return SCRIPT_OVERRIDE; } if (ai_lib.isInCombat(self)) { return SCRIPT_CONTINUE; } if (ai_lib.isInCombat(speaker)) { return SCRIPT_CONTINUE; } ai_lib.setMood(self, ai_lib.MOOD_CALM); stop(self); faceTo(self, speaker); messageTo(self, "handleAbortConversation", null, 30, false); return SCRIPT_CONTINUE; } public int handleAbortConversation(obj_id self, dictionary params) throws InterruptedException { if (!isInNpcConversation(self)) { if (getBehavior(self) <= BEHAVIOR_CALM) { messageTo(self, "resumeDefaultCalmBehavior", null, 5, false); } } return SCRIPT_CONTINUE; } public int OnEndNpcConversation(obj_id self, obj_id speaker) throws InterruptedException { LOGC(aiLoggingEnabled(self), "debug_ai", ("ai::OnEndNpcConversation() self(" + self + ":" + getName(self) + ") speaker(" + speaker + ":" + getName(speaker) + ")")); if (ai_lib.isAiDead(self)) { return SCRIPT_OVERRIDE; } if (getBehavior(self) <= BEHAVIOR_CALM) { messageTo(self, "resumeDefaultCalmBehavior", null, 5, false); } return SCRIPT_CONTINUE; } public int disableAI(obj_id self, dictionary params) throws InterruptedException { for (String script : getScriptList(self)) { if (script.startsWith("ai.")) { detachScript(self, script); } } stop(self); return SCRIPT_CONTINUE; } public int handleClearPathingFlag(obj_id self, dictionary params) throws InterruptedException { removeObjVar(self, "ai.pathingAwayFrom"); if (getBehavior(self) <= BEHAVIOR_CALM) { messageTo(self, "resumeDefaultCalmBehavior", null, 5, false); } return SCRIPT_CONTINUE; } public int handleAnimationAction(obj_id self, dictionary params) throws InterruptedException { String anim = params.getString("anim"); if (anim != null) { ai_lib.doAction(self, anim); } else { String animMood = params.getString("animMood"); if (animMood != null) { ai_lib.setMood(self, animMood); } } return SCRIPT_CONTINUE; } public int handleAddMaster(obj_id self, dictionary params) throws InterruptedException { obj_id pet = params.getObjId("pet"); if (!isIdValid(pet)) { return SCRIPT_CONTINUE; } if ((pet != self)) { return SCRIPT_CONTINUE; } obj_id controlDevice = params.getObjId("controlDevice"); if (!isIdValid(controlDevice)) { controlDevice = callable.getCallableCD(pet); } if (!isIdValid(controlDevice)) { return SCRIPT_CONTINUE; } obj_id master = params.getObjId("master"); if (!isIdValid(master)) { return SCRIPT_CONTINUE; } if (pet_lib.hasMaxPets(master, pet_lib.getPetType(self), pet) && callable.hasCallableCD(self)) { destroyObject(self); return SCRIPT_CONTINUE; } if (!hasScript(self, "ai.pet")) { setMaster(self, master); setOwner(utils.getInventoryContainer(self), master); attachScript(self, "ai.pet"); setObjVar(pet, "ai.pet.masterName", getEncodedName(master)); utils.removeScriptVar(self, "petBeingInitialized"); } if (!ai_lib.isMonster(self)) { pet_lib.setupDefaultCommands(self); } pet_lib.addToPetList(master, self); return SCRIPT_CONTINUE; } public int handleRemoveMaster(obj_id self, dictionary params) throws InterruptedException { if (!pet_lib.hasMaster(self)) { return SCRIPT_CONTINUE; } obj_id pet = params.getObjId("pet"); if (pet != self || !isIdValid(pet)) { return SCRIPT_CONTINUE; } params.put("master", getMaster(self)); final String creatureName = getCreatureName(self); if (creatureName != null) { params.put("ai.creatureName", creatureName); } queueCommand(pet, (1188179258), getGroupObject(pet), "", COMMAND_PRIORITY_DEFAULT); removeObjVar(pet, "ai.pet.masterName"); ai_lib.aiStopFollowing(pet); stop(pet); setMaster(pet, null); setOwner(utils.getInventoryContainer(self), obj_id.NULL_ID); removeTriggerVolume(ai_lib.ALERT_VOLUME_NAME); removeObjVar(pet, "ai.pet.friendList"); removeObjVar(pet, "ai.pet.guarding"); removeObjVar(pet, "ai.inFormation"); pet_lib.removeFromPetList(pet); if (hasScript(pet, "ai.pet")) { detachScript(pet, "ai.pet"); } messageTo(pet, "destroyAbandonedPet", null, 300, true); ai_lib.setDefaultCalmBehavior(pet, ai_lib.BEHAVIOR_LOITER); if (ai_lib.isMonster(pet)) { messageTo(pet, "handleWailingPet", null, 5, false); } return SCRIPT_CONTINUE; } public int handleWailingPet(obj_id self, dictionary params) throws InterruptedException { if (pet_lib.hasMaster(self) || ai_lib.isAiDead(self)) { return SCRIPT_CONTINUE; } switch (rand(1, 3)) { case 1: stop(self); ai_lib.doAction(self, "ashamed"); break; case 2: stop(self); ai_lib.doAction(self, "vocalize"); break; case 3: if (getBehavior(self) <= BEHAVIOR_CALM) { doDefaultCalmBehavior(self); } break; } messageTo(self, "handleWailingPet", null, 15, false); return SCRIPT_CONTINUE; } public int destroyAbandonedPet(obj_id self, dictionary params) throws InterruptedException { if (!pet_lib.hasMaster(self)) { destroyObject(self); } return SCRIPT_CONTINUE; } public boolean crossPortalBreach(obj_id npc, obj_id breacher) throws InterruptedException { return isIdValid(getLocation(npc).cell) != isIdValid(getLocation(breacher).cell) || !canSee(npc, breacher); } public void manageCrossPortalBreach(obj_id npc, obj_id breacher) throws InterruptedException { if (isPlayer(breacher)) { dictionary params = new dictionary(); params.put("breacher", breacher); messageTo(npc, "handleMonitorMovement", params, 5, false); } } public int handleMonitorMovement(obj_id self, dictionary params) throws InterruptedException { LOGC(aiLoggingEnabled(self), "debug_ai", "ai::handleMonitorMovement() self(" + self + ")"); if (ai_lib.isAiDead(self)) { return SCRIPT_CONTINUE; } obj_id breacher = params.getObjId("breacher"); if (!isIdValid(breacher) || !exists(breacher) || !isInWorld(breacher) || ai_lib.isAiDead(breacher)) { return SCRIPT_CONTINUE; } if (utils.getElementPositionInArray(getTriggerVolumeContents(self, ai_lib.ALERT_VOLUME_NAME), breacher) == -1) { return SCRIPT_CONTINUE; } obj_id yourCell = getLocation(breacher).cell; if (isIdValid(yourCell)) { if (yourCell != getLocation(self).cell) { messageTo(self, "handleMonitorMovement", params, 3, false); } else if (ai_lib.isInCombat(self)) { messageTo(self, "handleMonitorMovement", params, 3, false); } else { startCombat(self, breacher); } } return SCRIPT_CONTINUE; } public int OnAboutToBeTransferred(obj_id self, obj_id destContainer, obj_id transferer) throws InterruptedException { if (pet_lib.isPet(self)) { return SCRIPT_CONTINUE; } if (beast_lib.isBeast(self)) { return SCRIPT_CONTINUE; } obj_id bldg = getTopMostContainer(destContainer); if (isPlayer(bldg)) { return SCRIPT_CONTINUE; } if (!isIdValid(destContainer)) { return SCRIPT_CONTINUE; } boolean wontEnter = false; if (ai_lib.aiGetNiche(self) == NICHE_VEHICLE) { wontEnter = true; } if (!permissionsIsAllowed(destContainer, self)) { wontEnter = true; } if (wontEnter) { if (ai_lib.isInCombat(self)) { removeObjVar(self, "ai.combat.moveMode"); stop(self); } else { stop(self); pathTo(self, aiGetHomeLocation(self)); messageTo(self, "resumeDefaultCalmBehavior", null, 20, false); } return SCRIPT_OVERRIDE; } return SCRIPT_CONTINUE; } public boolean fightNotFlee(obj_id npc, obj_id threat) throws InterruptedException { LOGC(aiLoggingEnabled(npc), "debug_ai", "ai::fightNotFlee() npc(" + npc + ") threat(" + threat + ")"); if (hasObjVar(threat, "gm")) { return false; } if (!ai_lib.isInCombat(npc)) { if (factions.isAggro(npc) && factions.getFactionReaction(npc, threat) == factions.REACTION_NEGATIVE) { startCombat(npc, threat); return true; } if (pvpIsEnemy(npc, threat) && pvpCanAttack(npc, threat)) { startCombat(npc, threat); return true; } if (ai_lib.isMonster(npc) && ai_lib.isMonster(threat) && ai_lib.isAggro(npc)) { startCombat(npc, threat); return true; } if ((ai_lib.aiGetNiche(npc) == NICHE_CARNIVORE || ai_lib.aiGetNiche(npc) == NICHE_PREDATOR) && ai_lib.aiGetNiche(threat) == NICHE_HERBIVORE) { startCombat(npc, threat); return true; } } return false; } public int handleEntertainmentStart(obj_id self, dictionary params) throws InterruptedException { obj_id player = params.getObjId("entertainer"); if (!isIdValid(player)) { return SCRIPT_CONTINUE; } if (ai_lib.isInCombat(self) || ai_lib.aiIsDead(self)) { return SCRIPT_CONTINUE; } if (isInNpcConversation(self)) { return SCRIPT_CONTINUE; } if (!ai_lib.isInSameBuilding(self, player)) { return SCRIPT_CONTINUE; } if (hasScript(self, "ai.soldier") && !hasObjVar(self, gcw.GCW_ENTERTAINMENT_FLAG)) { return SCRIPT_CONTINUE; } if (instance.isInInstanceArea(self)) { return SCRIPT_CONTINUE; } if (hasObjVar(self, performance.NPC_ENTERTAINMENT_NO_ENTERTAIN)) { return SCRIPT_CONTINUE; } if (ai_lib.aiGetNiche(self) != NICHE_NPC) { return SCRIPT_CONTINUE; } if (getCreatureName(self).equals("darth_vader")) { return SCRIPT_CONTINUE; } if (hasObjVar(self, gcw.GCW_ENTERTAINMENT_FLAG) && !gcw.canEntertainGcwNonPlayingCharacter(player, self)) { return SCRIPT_CONTINUE; } if (hasObjVar(self, gcw.GCW_ENTERTAINMENT_FLAG) && utils.hasScriptVar(player, gcw.GCW_SCRIPTVAR_PARENT + ".gcwNpc")) { return SCRIPT_CONTINUE; } String entertainmentType = params.getString("perf_type"); String skillName = "healing_music_ability"; if (entertainmentType != null) { if (entertainmentType.equals(performance.PERFORMANCE_TYPE_DANCE)) { skillName = "healing_dance_ability"; } else if (entertainmentType.equals(performance.PERFORMANCE_TYPE_JUGGLE)) { skillName = "healing_juggle_ability"; } } int skillMod = rand(1, 100); if (entertainmentType != null) { skillMod = getSkillStatisticModifier(player, skillName); } if (skillMod == 0) { skillMod = rand(1, 100); } if (utils.hasScriptVar(self, "ai.listeningTo")) { int oldSkillMod = utils.getIntScriptVar(self, "ai.oldEntertainerSkillMod"); if (skillMod < oldSkillMod) { return SCRIPT_CONTINUE; } } if (hasObjVar(self, "faction_recruit_quest")) { if (!groundquests.isQuestActive(player, gcw.GCW_ENTERTAIN_RALLY)) { return SCRIPT_CONTINUE; } if ((factions.isImperialorImperialHelper(player) && factions.isImperialorImperialHelper(self) && !factions.isOnLeave(player)) || (factions.isRebelorRebelHelper(player) && factions.isRebelorRebelHelper(self) && !factions.isOnLeave(player))) { utils.setScriptVar(self, "faction_ent", player); messageTo(self, "readyToTalk", params, 20, false); params.put("lostInterestTime", getGameTime()); utils.setScriptVar(self, "lostInterestTime", getGameTime()); messageTo(self, "lostInterest", params, 60, false); } else { return SCRIPT_CONTINUE; } } utils.setScriptVar(self, "ai.oldEntertainerSkillMod", skillMod); if (!hasObjVar(self, "ai.oldYaw")) { setObjVar(self, "ai.oldYaw", getYaw(self)); } utils.setScriptVar(self, "ai.listeningTo", player); faceToBehavior(self, player); if (skillMod < 20) { if (rand(1, 2) == 1) { setAnimationMood(self, "npc_sad"); } else { setAnimationMood(self, "bored"); } } else if (skillMod < 50) { if (rand(1, 2) == 1) { setAnimationMood(self, "bored"); } else { setAnimationMood(self, "entertained"); } } else { setAnimationMood(self, "entertained"); } listenToMessage(player, "handlePerformerStopPerforming"); messageTo(self, "handleNoEntertainment", null, 30, false); if (hasObjVar(self, gcw.GCW_ENTERTAINMENT_FLAG)) { gcw.setEntertainGcwNonPlayerCharacter(player, self); } return SCRIPT_CONTINUE; } public int handleNoEntertainment(obj_id self, dictionary params) throws InterruptedException { boolean stopListening = false; if (!utils.hasScriptVar(self, "ai.listeningTo")) { return SCRIPT_CONTINUE; } obj_id player = utils.getObjIdScriptVar(self, "ai.listeningTo"); if (!isIdValid(player)) { stopListening = true; } else if (!exists(player) || !isInWorld(player) || !ai_lib.isInSameBuilding(self, player) || getPerformanceType(player) == 0) { stopListening = true; } if (stopListening) { utils.removeScriptVar(self, "ai.oldEntertainerSkillMod"); utils.removeScriptVar(self, "ai.listeningTo"); stop(self); messageTo(self, "resumeDefaultCalmBehavior", null, 0, false); } else { messageTo(self, "handleNoEntertainment", null, 30, false); } return SCRIPT_CONTINUE; } public int handlePerformerStopPerforming(obj_id self, dictionary params) throws InterruptedException { utils.notifyObject(self, "handleEntertainmentStop", params); return SCRIPT_CONTINUE; } public int handleEntertainmentStop(obj_id self, dictionary params) throws InterruptedException { obj_id player = obj_id.NULL_ID; if (params.containsKey("entertainer")) { player = params.getObjId("entertainer"); } else if (params.containsKey("performer")) { player = params.getObjId("performer"); } if (!isIdValid(player)) { return SCRIPT_CONTINUE; } if (utils.getObjIdScriptVar(self, "ai.listeningTo") != player) { return SCRIPT_CONTINUE; } if (ai_lib.aiIsDead(self) || ai_lib.isInCombat(self)) { return SCRIPT_CONTINUE; } setAnimationMood(self, "calm"); int skillMod = utils.getIntScriptVar(self, "ai.oldEntertainerSkillMod"); if (skillMod == 0) { skillMod = rand(1, 100); } if (skillMod < 20) { switch (rand(1, 4)) { case 1: doAnimationAction(self, "hold_nose"); break; case 2: doAnimationAction(self, "cover_ears_mocking"); break; case 3: doAnimationAction(self, "point_away"); break; case 4: doAnimationAction(self, "shake_head_no"); break; } } else if (skillMod < 40) { switch (rand(1, 4)) { case 1: doAnimationAction(self, "shake_head_no"); break; case 2: doAnimationAction(self, "applause_polite"); break; case 3: doAnimationAction(self, "yes"); break; case 4: doAnimationAction(self, "snap_finger1"); break; } } else if (skillMod < 60) { switch (rand(1, 4)) { case 1: doAnimationAction(self, "snap_finger1"); break; case 2: doAnimationAction(self, "applause_polite"); break; case 3: doAnimationAction(self, "yes"); break; case 4: doAnimationAction(self, "applause_excited"); break; } } else { switch (rand(1, 4)) { case 1: doAnimationAction(self, "applause_excited"); break; case 2: doAnimationAction(self, "clap_rousing"); break; case 3: doAnimationAction(self, "implore"); break; case 4: doAnimationAction(self, "applause_polite"); break; } } utils.removeScriptVar(self, "ai.oldEntertainerSkillMod"); utils.removeScriptVar(self, "ai.listeningTo"); stop(self); messageTo(self, "resumeDefaultCalmBehavior", null, 5, false); if (hasObjVar(self, gcw.GCW_ENTERTAINMENT_FLAG) && utils.hasScriptVar(self, gcw.GCW_SCRIPTVAR_PARENT + ".isGcwEntertained")) { LOG("gcw_entertainer", "NPC is saving time player stopped entertaining"); utils.setScriptVar(self, gcw.GCW_STOPPED_ENTERTAINING, getGameTime()); if (hasObjVar(self, gcw.GCW_PATROL_OBJ)) { obj_id patrolObject = getObjIdObjVar(self, gcw.GCW_PATROL_OBJ); if (isValidId(patrolObject)) { dictionary webster = new dictionary(); webster.put("npc", self); webster.put("player", player); messageTo(patrolObject, "handleOffensiveEntertainedNpcCleanUp", webster, 1, false); } } } return SCRIPT_CONTINUE; } public int OnEnteredCombat(obj_id self) throws InterruptedException { return SCRIPT_CONTINUE; } public int OnChangedPosture(obj_id self, int before, int after) throws InterruptedException { return SCRIPT_CONTINUE; } public int dizzyCheckFailed(obj_id self, dictionary params) throws InterruptedException { ai_lib.aiSetPosture(self, POSTURE_KNOCKED_DOWN); return SCRIPT_CONTINUE; } public int applyModTrap(obj_id self, dictionary params) throws InterruptedException { if (params == null) { return SCRIPT_CONTINUE; } if (utils.hasScriptVar(self, "trapmod.enable")) { return SCRIPT_CONTINUE; } java.util.Enumeration keys = params.keys(); while (keys.hasMoreElements()) { String key = (String)keys.nextElement(); if (!key.equals("prefix")) { utils.setScriptVar(self, "trapmod." + key, params.getInt(key)); } } utils.setScriptVar(self, "trapmod.enable", 1); messageTo(self, "removeModTrap", params, 60.0f, false); String prefix = params.getString("prefix"); showFlyText(self, new string_id("trap/trap", prefix + "_on"), 1.2f, colors.ORANGERED); obj_id[] players = getPlayerCreaturesInRange(self, 50.0f); for (obj_id player : players) { playClientEffectLoc(player, "clienteffect/combat_trap_" + prefix + ".cef", getLocation(self), 0.0f); } return SCRIPT_CONTINUE; } public int removeModTrap(obj_id self, dictionary params) throws InterruptedException { utils.removeScriptVar(self, "trapmod"); showFlyText(self, new string_id("trap/trap", params.getString("prefix") + "_off"), 1.2f, colors.ORANGERED); return SCRIPT_CONTINUE; } public int OnObjectMenuRequest(obj_id self, obj_id player, menu_info mi) throws InterruptedException { if (pet_lib.isPet(self) || beast_lib.isBeast(self)) { return SCRIPT_CONTINUE; } location here = getLocation(self); if (here == null) { LOG("designer_fatal", "ai.ai::OnObjectMenuRequest() -> getLocation(self) == null. WTF?!"); return SCRIPT_CONTINUE; } if (isIdValid(here.cell)) { return SCRIPT_CONTINUE; } obj_id myContainer = getContainedBy(self); if (!isIdValid(myContainer)) { return SCRIPT_CONTINUE; } destroyObject(self); return SCRIPT_CONTINUE; } public int OnObjectMenuSelect(obj_id self, obj_id player, int item) throws InterruptedException { return SCRIPT_CONTINUE; } public int OnDestroy(obj_id self) throws InterruptedException { obj_id group = getGroupObject(self); if (isIdValid(group)) { queueCommand(self, (1188179258), group, "", COMMAND_PRIORITY_DEFAULT); } return SCRIPT_CONTINUE; } public int forceAnimalAttack(obj_id self, dictionary params) throws InterruptedException { LOGC(aiLoggingEnabled(self), "debug_ai", "ai::forceAnimalAttack() self(" + self + ")"); if (ai_lib.aiIsDead(self)) { return SCRIPT_CONTINUE; } obj_id target = params.getObjId("target"); if (!isIdValid(target)) { return SCRIPT_CONTINUE; } if (!pvpCanAttack(self, target)) { return SCRIPT_CONTINUE; } utils.setScriptVar(self, "ai.combat.isTaunted", (getGameTime() + 20)); if (ai_lib.isInCombat(self)) { removeObjVar(self, "ai.combat.moveMode"); stop(self); setLookAtTarget(self, target); } else { startCombat(self, target); } return SCRIPT_CONTINUE; } public int attemptMilkHandler(obj_id self, dictionary params) throws InterruptedException { if (params == null) { return SCRIPT_CONTINUE; } attemptMilk(params.getObjId("player"), self); return SCRIPT_CONTINUE; } public void attemptMilk(obj_id player, obj_id self) throws InterruptedException { obj_id pInv = utils.getInventoryContainer(player); if (!isValidId(pInv) || !exists(pInv)) { return; } if (getVolumeFree(pInv) <= 0) { sendSystemMessage(self, SID_CANT_MILK_INV_FULL); return; } if (isIdValid(getMountId(player))) { sendSystemMessage(player, SID_CANT_MILK_MOUNTED); return; } if (utils.hasScriptVar(self, "milk.attempts")) { sendSystemMessage(player, SID_BEING_MILKED); return; } if (pet_lib.isPet(self) || beast_lib.isBeast(self)) { showFlyText(self, new string_id("npc_reaction/flytext", "threaten"), 2.0f, colors.ORANGERED); sendSystemMessage(player, SID_CANT_MILK); return; } if (stealth.hasInvisibleBuff(player)) { showFlyText(self, new string_id("npc_reaction/flytext", "threaten"), 2.0f, colors.ORANGERED); sendSystemMessage(player, SID_MILK_NOT_HIDDEN); return; } if (utils.hasScriptVar(self, "milk.lasttime")) { int milktime = utils.getIntScriptVar(self, "milk.lasttime"); if (getGameTime() - milktime < 3600) { showFlyText(self, new string_id("npc_reaction/flytext", "threaten"), 2.0f, colors.ORANGERED); sendSystemMessage(player, SID_CANT_MILK); return; } } float milkStunModified = 0.0f; if (buff.hasBuff(player, "creature_milking_buff") || buff.hasBuff(player, "drink_starshine_surprise")) { milkStunModified += getEnhancedSkillStatisticModifierUncapped(player, "milk_stun_modified"); CustomerServiceLog("milking_and_lair_search", "handleMilking: Player: " + getName(player) + " OID: " + player + " has a buff that gives a stun chance of: " + milkStunModified + "."); } if (milkStunModified > 0) { if (rand(1, 100) < milkStunModified) { CustomerServiceLog("milking_and_lair_search", "handleMilking: Player: " + getName(player) + " OID: " + player + " has successfully stunned creature " + self + ". The creature will stand still for a few seconds."); messageTo(self, "milkingCreatureStunned", null, 0, false); messageTo(self, "milkingCreatureStunRemoval", null, 4, false); } else { messageTo(self, "milkingCreatureStunFail", null, 0, false); CustomerServiceLog("milking_and_lair_search", "handleMilking: Player: " + getName(player) + " OID: " + player + " failed to stun the creature."); } } showFlyText(self, new string_id("npc_reaction/flytext", "alert"), 2.0f, colors.MEDIUMSLATEBLUE); sendSystemMessage(player, SID_MILK_BEGIN); utils.setScriptVar(self, "milk.attempts", 0); dictionary params = new dictionary(); params.put("player", player); messageTo(self, "handleMilking", params, 7, false); } public int handleMilking(obj_id self, dictionary params) throws InterruptedException { obj_id player = params.getObjId("player"); if (isDead(self)) { sendSystemMessage(player, SID_CANT_MILK_THE_DEAD); return SCRIPT_CONTINUE; } if (isIdValid(getMountId(player))) { sendSystemMessage(player, SID_CANT_MILK_MOUNTED); return SCRIPT_CONTINUE; } float dist = getDistance(self, player); if ((dist < -3) || (dist > 3)) { showFlyText(self, new string_id("npc_reaction/flytext", "threaten"), 2.0f, colors.ORANGERED); sendSystemMessage(player, SID_MILK_TOO_FAR); utils.removeScriptVar(self, "milk.attempts"); return SCRIPT_CONTINUE; } if (stealth.hasInvisibleBuff(player) || ai_lib.isInCombat(self) || ai_lib.isInCombat(player)) { showFlyText(self, new string_id("npc_reaction/flytext", "threaten"), 2.0f, colors.ORANGERED); sendSystemMessage(player, SID_MILK_NOT_HIDDEN); utils.removeScriptVar(self, "milk.attempts"); return SCRIPT_CONTINUE; } int attempts = utils.getIntScriptVar(self, "milk.attempts"); attempts++; utils.setScriptVar(self, "milk.attempts", attempts); boolean shortenAttempts = false; float milkQuantityModified = 0.0f; float milkExceptionalModified = 0.0f; if (buff.hasBuff(player, "creature_milking_buff") || buff.hasBuff(player, "drink_starshine_surprise")) { if (buff.hasBuff(player, "creature_milking_buff")) { CustomerServiceLog("buff", "creature_milking_buff Buff used by player: " + player + " Name: " + getName(player) + " has creature_milking_buff "); } else if (buff.hasBuff(player, "drink_starshine_surprise")) { CustomerServiceLog("buff", "creature_milking_buff Buff used by player: " + player + " Name: " + getName(player) + " has drink_starshine_surprise buff "); } milkExceptionalModified += getEnhancedSkillStatisticModifierUncapped(player, "milk_exceptional_modified"); CustomerServiceLog("buff", "creature_milking_buff Buff used by player: " + player + " Name: " + getName(player) + " has a exceptional milk modifier of: " + milkExceptionalModified); milkQuantityModified += getEnhancedSkillStatisticModifierUncapped(player, "milk_quantity_modified"); CustomerServiceLog("buff", "creature_milking_buff Buff used by player: " + player + " Name: " + getName(player) + " has a milk quantity modifier of: " + milkQuantityModified); shortenAttempts = true; } if (attempts == 3 || shortenAttempts) { obj_id pInv = utils.getInventoryContainer(player); if (!isValidId(pInv) || !exists(pInv)) { return SCRIPT_CONTINUE; } else if (getVolumeFree(pInv) <= 0) { sendSystemMessage(self, SID_CANT_MILK_INV_FULL); return SCRIPT_CONTINUE; } int lev = ai_lib.getLevel(self); if (lev > 50) { lev = 50; } int mlev = lev / 2; if (mlev < 1) { mlev = 1; } int amt = rand(mlev * 10, lev * 10); if (shortenAttempts && milkQuantityModified > 0) { amt = amt + (int)(amt * milkQuantityModified); } String resourceType = ai_lib.getMilkType(self); if (resourceType == null || resourceType.equals("")) { CustomerServiceLog("milking_and_lair_search", "handleMilking: Player: " + getName(player) + " OID: " + player + " attempted to milk but could not retrieve a valid milk type on " + self + " " + getName(self)); blog("ai.handleMilking: cannot get resource type from ai_lib.getMilkType"); return SCRIPT_CONTINUE; } String sceneName = getCurrentSceneName(); if (sceneName == null || sceneName.equals("")) { CustomerServiceLog("milking_and_lair_search", "handleMilking: Player: " + getName(player) + " OID: " + player + " attempted to milk but could not retrieve a valid scene name (planet name) while milking " + self + " " + getName(self)); blog("ai.handleMilking: cannot get scene name"); return SCRIPT_CONTINUE; } String rsrcMapTable = "datatables/creature_resource/resource_scene_map.iff"; String correctedPlanetName = dataTableGetString(rsrcMapTable, sceneName, 1); if (correctedPlanetName == null || correctedPlanetName.equals("")) { correctedPlanetName = "tatooine"; CustomerServiceLog("milking_and_lair_search", "handleMilking: Player: " + getName(player) + " OID: " + player + " attempted to milk but received an invlaid Planet Name. As a result the milk resource planet attrib has been defaulted to TATOOINE."); } resourceType = resourceType + "_" + correctedPlanetName; int useDistMap = dataTableGetInt(rsrcMapTable, sceneName, "useDistributionMap"); if (useDistMap < 0) { blog("ai.handleMilking: cannot get int data from distribution data table"); CustomerServiceLog("milking_and_lair_search", "handleMilking: Player: " + getName(player) + " OID: " + player + " attempted to milk but could not retrieve resource distribution data while milking " + self + " " + getName(self)); return SCRIPT_CONTINUE; } location worldLoc = getWorldLocation(self); if (worldLoc == null) { blog("ai.handleMilking: cannot get world location from cpp"); CustomerServiceLog("milking_and_lair_search", "handleMilking: Player: " + getName(player) + " OID: " + player + " attempted to milk but could not retrieve world location while milking " + self + " " + getName(self)); return SCRIPT_CONTINUE; } if (useDistMap == 0) { worldLoc.area = correctedPlanetName; } obj_id[] resourceList = resource.createRandom(resourceType, amt, worldLoc, pInv, player, 2); if (resourceList == null) { blog("ai.handleMilking: cannot get resource data from resource.createRandom function"); CustomerServiceLog("milking_and_lair_search", "handleMilking: Player: " + getName(player) + " OID: " + player + " attempted to milk but could not resource data from resource.createRandom function while milking " + self + " " + getName(self)); return SCRIPT_CONTINUE; } location curloc = getLocation(player); if (curloc == null) { blog("ai.handleMilking: cannot get resource data from getLocation cpp"); CustomerServiceLog("milking_and_lair_search", "handleMilking: Player: " + getName(player) + " OID: " + player + " attempted to milk but could not retrieve location data while milking " + self + " " + getName(self)); return SCRIPT_CONTINUE; } for (obj_id obj_id : resourceList) { blog("" + obj_id); setLocation(obj_id, curloc); putIn(obj_id, pInv, player); } sendSystemMessage(player, SID_MILK_SUCCESS); utils.setScriptVar(self, "milk.lasttime", getGameTime()); utils.removeScriptVar(self, "milk.attempts"); if (!collection.collectionResource(player, "milk", (int)milkExceptionalModified)) { blog("ai.handleMilking: cannot get resource data from getLocation cpp"); CustomerServiceLog("milking_and_lair_search", "handleMilking: Player: " + getName(player) + " OID: " + player + " did not receive an exceptional milk from creature " + self + " " + getName(self) + ". Check the collection logs for additional details."); return SCRIPT_CONTINUE; } return SCRIPT_CONTINUE; } else { sendSystemMessage(player, SID_MILK_CONTINUE); } messageTo(self, "handleMilking", params, 7, false); return SCRIPT_CONTINUE; } public int handleSpawnParameters(obj_id self, dictionary params) throws InterruptedException { LOGC(aiLoggingEnabled(self), "debug_ai", "ai::handleSpawnParameters() self(" + self + ")"); if (params == null || params.isEmpty()) { return SCRIPT_CONTINUE; } obj_id target = params.getObjId("actionTarget"); switch (params.getInt("actionCode")) { case gcw.AC_ATTACK: if (isIdValid(target)) { startCombat(self, target); } break; case gcw.AC_SCAN: int scanInterests = params.getInt("scanInterests"); if (scanInterests == 0) { gcw.assignScanInterests(self); } else { utils.setScriptVar(self, gcw.SCRIPTVAR_SCAN_INTEREST, scanInterests); } gcw.harass(self, target); break; default: break; } return SCRIPT_CONTINUE; } public int playDelayedClientEffect(obj_id self, dictionary params) throws InterruptedException { obj_id target = params.getObjId("target"); playClientEffectObj(target, params.getString("effect"), target, ""); return SCRIPT_CONTINUE; } public int clearScriptVar(obj_id self, dictionary params) throws InterruptedException { utils.removeScriptVar(self, params.getString("name")); return SCRIPT_CONTINUE; } public int OnInvulnerableChanged(obj_id self, boolean invulnerable) throws InterruptedException { LOGC(aiLoggingEnabled(self), "debug_ai", "ai::OnInvulnerableChanged() self(" + self + ") invulerable(" + invulnerable + ")"); if (invulnerable) { removeTriggerVolume(ai_lib.ALERT_VOLUME_NAME); removeTriggerVolume(ai_lib.AGGRO_VOLUME_NAME); } else { ai_lib.resetCombatTriggerVolumes(); } return SCRIPT_CONTINUE; } public int OnIncapacitateTarget(obj_id self, obj_id victim) throws InterruptedException { if (!utils.hasScriptVar(self, "experienced")) { if (isIdValid(victim)) { if (isPlayer(victim)) { if (rand(1, 1000) == 999) { ai_lib.creatureLevelUp(self, victim); utils.setScriptVar(self, "experienced", 1); } } } } return SCRIPT_CONTINUE; } public int clearCollectionCameraParticle(obj_id self, dictionary params) throws InterruptedException { obj_id target = params.getObjId("target"); stopClientEffectObjByLabel(target, "root_buff"); utils.removeScriptVar(target, "picture_taken_debuff"); return SCRIPT_CONTINUE; } public int OnGiveItem(obj_id self, obj_id item, obj_id giver) throws InterruptedException { if (!hasCompletedCollectionSlot(giver, "meatlump_recruiter_starter")) { return SCRIPT_CONTINUE; } if (!isIdValid(giver) || !exists(giver)) { return SCRIPT_CONTINUE; } if (!isIdValid(item) || !exists(item)) { return SCRIPT_CONTINUE; } if (!getStaticItemName(item).equals("col_meatlump_recruit_manual_02_01")) { return SCRIPT_CONTINUE; } String mobName = getCreatureName(self); String socialMeatlump = dataTableGetString(CREATURE_TABLE, mobName, "socialGroup"); if (socialMeatlump != null && (socialMeatlump.startsWith("meatlump") || socialMeatlump.endsWith("meatlump"))) { if (ai_lib.isNpc(self)) { sendSystemMessage(giver, SID_ALREADY_RECRUITED); } return SCRIPT_CONTINUE; } if (socialMeatlump != null && ((toLower(socialMeatlump)).equals("rebel") || (toLower(socialMeatlump)).equals("rebel"))) { if (ai_lib.isNpc(self)) { sendSystemMessage(giver, SID_NO_RECRUIT_REB_IMP); } return SCRIPT_CONTINUE; } if (hasCompletedCollection(giver, "col_meatlump_recruiter_01")) { return SCRIPT_CONTINUE; } if (utils.hasScriptVar(self, "collection.recruited")) { sendSystemMessage(giver, SID_ALREADY_RECRUITED); return SCRIPT_CONTINUE; } if (utils.hasScriptVar(self, "collection.investigator")) { sendSystemMessage(giver, SID_ENEMY_RECRUIT); return SCRIPT_CONTINUE; } if (!ai_lib.isNpc(self)) { return SCRIPT_CONTINUE; } if (!isInvulnerable(self)) { return SCRIPT_CONTINUE; } if (rand(1, 100) <= 10) { chat.chat(self, SID_NPC_MEATLUMP_SPEAK); float searchSize = 12.0f; obj_id mob = null; int mobLevel = getLevel(giver) - 2; location currentLoc = getLocation(giver); location locGoodLocation = locations.getGoodLocationAroundLocationAvoidCollidables(currentLoc, searchSize, searchSize, searchSize, searchSize, false, false, 6.0f); if (locGoodLocation == null) { locGoodLocation = (location)currentLoc.clone(); } int mobCount = rand(1, 3); if (utils.isProfession(giver, utils.TRADER)) { mobCount = 2; } if (mobCount == 1) { mob = create.object("mtp_recruiter_corsec_detective", locGoodLocation, mobLevel); } if (mobCount == 2) { mob = create.object("mtp_recruiter_corsec_investigator", locGoodLocation, mobLevel); } if (mobCount == 3) { mob = create.object("mtp_recruiter_corsec_agent", locGoodLocation, mobLevel); } addHate(mob, giver, 1000.0f); utils.setScriptVar(self, "collection.investigator", 1); messageTo(self, "removeMeatlumpInvestigatorScriptVar", null, 82800, false); } else { sendSystemMessage(giver, SID_GAVE_RECRUIT_ITEM); int count = getCount(item); count--; if (count <= 0) { detachScript(item, "item.special.nodestroy"); destroyObject(item); } else { setCount(item, count); } modifyCollectionSlotValue(giver, "meatlump_recruiter_01", 1); utils.setScriptVar(self, "collection.recruited", 1); messageTo(self, "removeMeatlumpRecruitmentScriptVar", null, 82800, false); } return SCRIPT_CONTINUE; } public int removeMeatlumpRecruitmentScriptVar(obj_id self, dictionary params) throws InterruptedException { utils.removeScriptVar(self, "collection.recruited"); return SCRIPT_CONTINUE; } public int removeMeatlumpInvestigatorScriptVar(obj_id self, dictionary params) throws InterruptedException { utils.removeScriptVar(self, "collection.investigator"); return SCRIPT_CONTINUE; } public int milkingCreatureStunned(obj_id self, dictionary params) throws InterruptedException { showFlyText(self, new string_id("npc_reaction/flytext", "stun"), 2.0f, colors.ORANGERED); ai_lib.setDefaultCalmBehavior(self, ai_lib.BEHAVIOR_SENTINEL); return SCRIPT_CONTINUE; } public int milkingCreatureStunFail(obj_id self, dictionary params) throws InterruptedException { showFlyText(self, new string_id("npc_reaction/flytext", "stun_fail"), 2.0f, colors.ORANGERED); return SCRIPT_CONTINUE; } public int milkingCreatureStunRemoval(obj_id self, dictionary params) throws InterruptedException { showFlyText(self, new string_id("npc_reaction/flytext", "stun_expired"), 2.0f, colors.ORANGERED); ai_lib.setDefaultCalmBehavior(self, ai_lib.BEHAVIOR_LOITER); return SCRIPT_CONTINUE; } public int redoYaw(obj_id self, dictionary params) throws InterruptedException { obj_id target = params.getObjId("target"); if (hasObjVar(target, "ai.yaw")) { float yaw_ai = getFloatObjVar(target, "ai.yaw"); setYaw(target, yaw_ai); } return SCRIPT_CONTINUE; } public boolean blog(String msg) throws InterruptedException { LOG(LOGGING_CATEGORY, msg); return true; } }