Files
dsrc/sku.0/sys.server/compiled/game/script/library/ai_lib.scriptlib
T
2013-09-10 23:17:15 -07:00

2146 lines
47 KiB
Plaintext

include library.beast_lib;
include library.buff;
include library.chat;
include library.combat_consts;
include library.dot;
include library.locations;
include library.pet_lib;
include library.skill;
include library.movement;
const float PLAYER_RUN_SPEED = 8f;
const float AI_MAX_MOVEMENT_SPEED = PLAYER_RUN_SPEED;
const string ALERT_VOLUME_NAME = "alertTriggerVolume";
const string AGGRO_VOLUME_NAME = "aggroTriggerVolume";
const string MOOD_CALM = "calm";
const string MOOD_NERVOUS = "nervous";
const string MOOD_THREATEN = "threaten";
const int BEHAVIOR_WANDER = 0;//zero is always default behavior
const int BEHAVIOR_SENTINEL = 1;
const int BEHAVIOR_LOITER = 2;
const int BEHAVIOR_STOP = 3;
const string DIF_VERY_EASY = "veryEasy";
const string DIF_EASY = "easy";
const string DIF_MEDIUM = "medium";
const string DIF_HARD = "hard";
const string DIF_VERY_HARD = "veryHard";
const string ALLY_LIST = "allyList";
const string CREATURE_TABLE = "datatables/mob/creatures.iff";
const string CREATURE_NAME_FILE = "mob/creature_names";
const string ACTION_ALERT = "alert";
const string ACTION_THREATEN = "threaten";
const string_id SMUGGLER_SCAN_SUCCESS = new string_id("base_player","smuggler_scan_success");
const string_id SMUGGLER_SCAN_FAIL = new string_id("base_player","smuggler_scan_fail");
const float DEFAULT_FOLLOW_MIN = 4f;
const float DEFAULT_FOLLOW_MAX = 8f;
const string OBJVAR_ATTACKABLE_OVERRIDE = "ai_combat.attackable";
const string SCRIPTVAR_CACHED_PATROL_PATH = "ai.patrolPath";
const string SCRIPTVAR_CACHED_PATROL_NAMED_PATH = "ai.patrolNamedPath";
const string SCRIPTVAR_CACHED_PATROL_TYPE = "ai.patrolType";
const int PATROL_FLAG_RANDOM = 0x0001;
const int PATROL_FLAG_FLIP = 0x0002;
const int PATROL_FLAG_REPEAT = 0x0004;
const int FORMATION_COLUMN = 0;
const int FORMATION_WEDGE = 1;
const int FORMATION_LINE = 2;
const int FORMATION_BOX = 3;
const int DIFFICULTY_NORMAL = 0;
const int DIFFICULTY_ELITE = 1;
const int DIFFICULTY_BOSS = 2;
const string SHARED_HEALTH_LIST = "shared_health_list";
boolean isWithinLeash(obj_id ai)
{
const float distanceToHome = getDistance(getLocation(ai), aiGetLeashAnchorLocation(ai));
const float leashRadius = aiGetLeashRadius();
return (distanceToHome <= leashRadius);
}
void resetAi()
{
const obj_id self = getSelf();
LOGC(aiLoggingEnabled(self), "debug_ai", ("ai_lib::resetAi() --- BEGIN RESET AI --- self(" + self + ") getName(" + getName(self) + ")"));
setMovementWalk(self);
movement.refresh(self);
resetCombatTriggerVolumes();
// The delay in this messageTo is to allow the object to complete creation
messageTo(self, "resumeDefaultCalmBehavior", null, 1, false);
LOGC(aiLoggingEnabled(self), "debug_ai", ("ai_lib::resetAi() --- END RESET AI --- self(" + self + ") getName(" + getName(self) + ")"));
}
void resetCombatTriggerVolumes()
{
const obj_id self = getSelf();
LOGC(aiLoggingEnabled(self), "debug_ai", ("ai_lib::resetCombatTriggerVolumes() self(" + self + ") getName(" + getName(self) + ")"));
// Invulnerable AI or non-aggressive animals never need combat trigger volumes
boolean needsCombatTriggerVolumes = true;
if (isInvulnerable(self))
{
needsCombatTriggerVolumes = false;
}
else if (isAnimal(self) && !aiIsAggressive(self))
{
needsCombatTriggerVolumes = false;
}
else if ( isVehicleMine(self) )
{
needsCombatTriggerVolumes = false;
}
else if (beast_lib.isBeast(self))
{
needsCombatTriggerVolumes = false;
}
if (needsCombatTriggerVolumes)
{
// Create ALERT trigger volume
{
const boolean promiscuous = true;
const float alertRadius = 64.0f;
createTriggerVolume(ai_lib.ALERT_VOLUME_NAME, alertRadius, promiscuous);
}
// Create AGGRO trigger volume, AI needs an aggro trigger volume because they could be factionally aggressive towards something
{
const boolean promiscuous = false;
const float aggroRadius = aiGetAggroRadius(self);
createTriggerVolume(ai_lib.AGGRO_VOLUME_NAME, aggroRadius, promiscuous);
}
}
}
void clearCombatData()
{
const obj_id self = getSelf();
clearHateList(self);
queueClear(self);
pclib.clearCombatData(self);
movement.removeAllModifiers(self);
buff.removeAllBuffs(self);
dot.removeAllDots(self);
removeTriggerVolume(ai_lib.ALERT_VOLUME_NAME);
removeTriggerVolume(ai_lib.AGGRO_VOLUME_NAME);
}
boolean isInCombat(obj_id ai)
{
return (getState(ai, STATE_COMBAT) == 1);
}
void setAttackable( obj_id npc, boolean val)
{
if(val)
setObjVar(npc, OBJVAR_ATTACKABLE_OVERRIDE, 1);
else if(hasObjVar(npc, OBJVAR_ATTACKABLE_OVERRIDE))
removeObjVar(npc, OBJVAR_ATTACKABLE_OVERRIDE);
}
boolean isAttackable( obj_id npc )
{
return hasObjVar(npc, OBJVAR_ATTACKABLE_OVERRIDE);
}
//obj_id getBehaviorTarget( obj_id npc, int behavior )
//{
// obj_id[] allTargets = getBehaviorTargets( npc, behavior );
// obj_id bestTarget = null;
//
// if ( allTargets == null || allTargets.length == 0 )
// return null;
//
// for ( int i = 0; i < allTargets.length; i++ )
// {
// if (isInWorld( allTargets[i] ) && !ai_lib.isAiDead( allTargets[i] ) && getDistance( npc, allTargets[i] ) < combat_engine.getMaxCombatRange() )
// return allTargets[i];
// }
// //debugSpeakMsg( npc, "all my targets were incapacitated" );
// return bestTarget;
//}
void setMood( obj_id npc, string mood )
{
//debugSpeakMsg( npc, "SETTING MOOD : " + mood );
obj_id thisNpc = getSelf();
if ( thisNpc != npc )
{
//debugSpeakMsg( npc, "sending a callback" );
dictionary parms = new dictionary();
parms.put( "animMood", mood );
messageTo( npc, "handleAnimationAction", parms, 1, false );
return;
}
if ( ai_lib.isAiDead( npc ) )
{
//debugSpeakMsg( npc, "i am dead" );
return;
}
//debugSpeakMsg( npc, "mood: " + mood );
if ( mood == MOOD_CALM )
{
//debugSpeakMsg( npc, "calm" );
removeObjVar( npc, "ai.mood" );
}
else
{
//debugSpeakMsg( npc, "mood " + mood );
setObjVar( npc, "ai.mood", mood );
}
if ( mood == MOOD_THREATEN )
{
//debugSpeakMsg( npc, "threaten!" );
chat.setAngryMood( npc );
ai_lib.barkString( npc, "threat" );
}
else if ( mood == MOOD_NERVOUS )
{
//debugSpeakMsg( npc, "alert!" );
chat.setBadMood( npc );
ai_lib.barkString( npc, "alert" );
}
if ( mood == MOOD_CALM && hasObjVar( npc, "ai.defaultCalmMood" ) )
{
//debugSpeakMsg( npc, "calm and has objvar" );
mood = getStringObjVar( npc, "ai.defaultCalmMood" );
//debugSpeakMsg( npc, "animood is " + mood);
}
else
{
//debugSpeakMsg( npc, "no objvar or not calm so setting mood " + mood );
}
setAnimationMood( npc, mood );
}
void doAction( obj_id npc, string anim )
{
obj_id thisNpc = getSelf();
if ( thisNpc != npc )
{
dictionary parms = new dictionary();
parms.put( "anim", anim );
messageTo( npc, "handleAnimationAction", parms, 1, false );
return;
}
if ( ai_lib.isAiDead( npc ) )
return;
//debugSpeakMsg( npc, "doing anim " + anim );
int npcPosture = getPosture( npc );
if ( npcPosture != POSTURE_UPRIGHT )
{
if ( npcPosture != POSTURE_KNOCKED_DOWN )
posture.stand(npc);
//debugSpeakMsg( npc, "stopping to stand so I can animate" );
removeObjVar( npc, "ai.combat.moveMode" );
}
else
{
doAnimationAction( npc, anim );
}
}
void setPatrolPath( obj_id npc, string[] waypoints )
{
setPatrolPath(npc, waypoints, 0);
}
void setPatrolPath( obj_id npc, string[] waypoints, int startPoint )
{
if ( isIdValid(npc) && waypoints != null )
{
location[] patrolLocs = parseWaypoints( npc, waypoints );
if ( patrolLocs != null )
setPatrolPath(npc, patrolLocs, startPoint);
}
}
void setPatrolOncePath( obj_id npc, string[] waypoints )
{
setPatrolOncePath(npc, waypoints, 0);
}
void setPatrolOncePath( obj_id npc, string[] waypoints, int startPoint )
{
if ( isIdValid(npc) && waypoints != null )
{
location[] patrolLocs = parseWaypoints( npc, waypoints );
if ( patrolLocs != null )
setPatrolOncePath(npc, patrolLocs, startPoint);
}
}
void setPatrolRandomPath( obj_id npc, string[] waypoints )
{
if ( isIdValid(npc) && waypoints != null )
{
location[] patrolLocs = parseWaypoints( npc, waypoints );
if ( patrolLocs != null )
setPatrolRandomPath(npc, patrolLocs);
}
}
void setPatrolRandomOncePath( obj_id npc, string[] waypoints )
{
if ( isIdValid(npc) && waypoints != null )
{
location[] patrolLocs = parseWaypoints( npc, waypoints );
if ( patrolLocs != null )
setPatrolRandomOncePath(npc, patrolLocs);
}
}
void setPatrolFlipPath( obj_id npc, string[] waypoints )
{
setPatrolFlipPath(npc, waypoints, 0);
}
void setPatrolFlipPath( obj_id npc, string[] waypoints, int startPoint )
{
if ( isIdValid(npc) && waypoints != null )
{
location[] patrolLocs = parseWaypoints( npc, waypoints );
if ( patrolLocs != null )
setPatrolFlipPath(npc, patrolLocs, startPoint);
}
}
void setPatrolFlipOncePath( obj_id npc, string[] waypoints )
{
setPatrolFlipOncePath(npc, waypoints, 0);
}
void setPatrolFlipOncePath( obj_id npc, string[] waypoints, int startPoint )
{
if ( isIdValid(npc) && waypoints != null )
{
location[] patrolLocs = parseWaypoints( npc, waypoints );
if ( patrolLocs != null )
setPatrolFlipOncePath(npc, patrolLocs, startPoint);
}
}
void setPatrolPath( obj_id npc, location[] patrolLoc )
{
setPatrolPath(npc, patrolLoc, 0);
}
void setPatrolPath( obj_id npc, location[] patrolLoc, int startPoint )
{
LOGC(aiLoggingEnabled(npc), "debug_ai", ("ai_lib::setPatrolPath() self(" + npc + ") getName(" + getName(npc) + ") patrolLength(" + patrolLoc + ")"));
if ( isIdValid(npc) && patrolLoc != null )
{
utils.setScriptVar(npc, SCRIPTVAR_CACHED_PATROL_PATH, patrolLoc);
utils.setScriptVar(npc, SCRIPTVAR_CACHED_PATROL_TYPE, PATROL_FLAG_REPEAT);
patrol(npc, patrolLoc, startPoint);
}
}
void setPatrolOncePath(obj_id npc, location[] patrolLoc)
{
setPatrolOncePath(npc, patrolLoc, 0);
}
void setPatrolOncePath(obj_id npc, location[] patrolLoc, int startPoint)
{
if ( isIdValid(npc) && patrolLoc != null )
{
utils.setScriptVar(npc, SCRIPTVAR_CACHED_PATROL_PATH, patrolLoc);
utils.setScriptVar(npc, SCRIPTVAR_CACHED_PATROL_TYPE, 0);
patrolOnce(npc, patrolLoc, startPoint);
}
}
void setPatrolRandomPath(obj_id npc, location[] patrolLoc)
{
if ( isIdValid(npc) && patrolLoc != null )
{
utils.setScriptVar(npc, SCRIPTVAR_CACHED_PATROL_PATH, patrolLoc);
utils.setScriptVar(npc, SCRIPTVAR_CACHED_PATROL_TYPE, PATROL_FLAG_RANDOM | PATROL_FLAG_REPEAT);
patrolRandom(npc, patrolLoc);
}
}
void setPatrolRandomOncePath(obj_id npc, location[] patrolLoc)
{
if ( isIdValid(npc) && patrolLoc != null )
{
utils.setScriptVar(npc, SCRIPTVAR_CACHED_PATROL_PATH, patrolLoc);
utils.setScriptVar(npc, SCRIPTVAR_CACHED_PATROL_TYPE, PATROL_FLAG_RANDOM);
patrolRandomOnce(npc, patrolLoc);
}
}
void setPatrolFlipPath(obj_id npc, location[] patrolLoc)
{
setPatrolFlipPath(npc, patrolLoc, 0);
}
void setPatrolFlipPath(obj_id npc, location[] patrolLoc, int startPoint)
{
if ( isIdValid(npc) && patrolLoc != null )
{
utils.setScriptVar(npc, SCRIPTVAR_CACHED_PATROL_PATH, patrolLoc);
utils.setScriptVar(npc, SCRIPTVAR_CACHED_PATROL_TYPE, PATROL_FLAG_FLIP | PATROL_FLAG_REPEAT);
patrolFlip(npc, patrolLoc, startPoint);
}
}
void setPatrolFlipOncePath(obj_id npc, location[] patrolLoc)
{
setPatrolFlipOncePath(npc, patrolLoc, 0);
}
void setPatrolFlipOncePath(obj_id npc, location[] patrolLoc, int startPoint)
{
if ( isIdValid(npc) && patrolLoc != null )
{
utils.setScriptVar(npc, SCRIPTVAR_CACHED_PATROL_PATH, patrolLoc);
utils.setScriptVar(npc, SCRIPTVAR_CACHED_PATROL_TYPE, PATROL_FLAG_FLIP);
patrolFlipOnce(npc, patrolLoc, startPoint);
}
}
void setPatrolNamedPath( obj_id npc, string[] patrolLoc )
{
setPatrolNamedPath(npc, patrolLoc, 0);
}
void setPatrolNamedPath( obj_id npc, string[] patrolLoc, int startPoint )
{
if ( isIdValid(npc) && patrolLoc != null )
{
utils.setScriptVar(npc, SCRIPTVAR_CACHED_PATROL_NAMED_PATH, patrolLoc);
utils.setScriptVar(npc, SCRIPTVAR_CACHED_PATROL_TYPE, PATROL_FLAG_REPEAT);
patrol(npc, patrolLoc, startPoint);
}
}
void setPatrolOnceNamedPath(obj_id npc, string[] patrolLoc)
{
setPatrolOnceNamedPath(npc, patrolLoc, 0);
}
void setPatrolOnceNamedPath(obj_id npc, string[] patrolLoc, int startPoint)
{
if ( isIdValid(npc) && patrolLoc != null )
{
utils.setScriptVar(npc, SCRIPTVAR_CACHED_PATROL_NAMED_PATH, patrolLoc);
utils.setScriptVar(npc, SCRIPTVAR_CACHED_PATROL_TYPE, 0);
patrolOnce(npc, patrolLoc, startPoint);
}
}
void setPatrolRandomNamedPath(obj_id npc, string[] patrolLoc)
{
if ( isIdValid(npc) && patrolLoc != null )
{
if ( !exists(npc) )
{
LOG("debug_ai", "WARNING: ai_lib.setPatrolRandomNamedPath passed npc id " + npc + " that doesn't exist");
return;
}
else if ( !isGameObjectTypeOf(npc, GOT_creature) )
{
LOG("debug_ai", "WARNING: ai_lib.setPatrolRandomNamedPath passed npc id " + npc + " that is not a creature. "+
"Object template = " + getTemplateName(npc));
}
utils.setScriptVar(npc, SCRIPTVAR_CACHED_PATROL_NAMED_PATH, patrolLoc);
utils.setScriptVar(npc, SCRIPTVAR_CACHED_PATROL_TYPE, PATROL_FLAG_RANDOM | PATROL_FLAG_REPEAT);
patrolRandom(npc, patrolLoc);
}
}
void setPatrolRandomOnceNamedPath(obj_id npc, string[] patrolLoc)
{
if ( isIdValid(npc) && patrolLoc != null )
{
utils.setScriptVar(npc, SCRIPTVAR_CACHED_PATROL_NAMED_PATH, patrolLoc);
utils.setScriptVar(npc, SCRIPTVAR_CACHED_PATROL_TYPE, PATROL_FLAG_RANDOM);
patrolRandomOnce(npc, patrolLoc);
}
}
void setPatrolFlipNamedPath(obj_id npc, string[] patrolLoc)
{
setPatrolFlipNamedPath(npc, patrolLoc, 0);
}
void setPatrolFlipNamedPath(obj_id npc, string[] patrolLoc, int startPoint)
{
if ( isIdValid(npc) && patrolLoc != null )
{
utils.setScriptVar(npc, SCRIPTVAR_CACHED_PATROL_NAMED_PATH, patrolLoc);
utils.setScriptVar(npc, SCRIPTVAR_CACHED_PATROL_TYPE, PATROL_FLAG_FLIP | PATROL_FLAG_REPEAT);
patrolFlip(npc, patrolLoc, startPoint);
}
}
void setPatrolFlipOnceNamedPath(obj_id npc, string[] patrolLoc)
{
setPatrolFlipOnceNamedPath(npc, patrolLoc, 0);
}
void setPatrolFlipOnceNamedPath(obj_id npc, string[] patrolLoc, int startPoint)
{
if ( isIdValid(npc) && patrolLoc != null )
{
utils.setScriptVar(npc, SCRIPTVAR_CACHED_PATROL_NAMED_PATH, patrolLoc);
utils.setScriptVar(npc, SCRIPTVAR_CACHED_PATROL_TYPE, PATROL_FLAG_FLIP);
patrolFlipOnce(npc, patrolLoc, startPoint);
}
}
void clearPatrolPath(obj_id npc)
{
if ( isIdValid(npc) )
{
utils.removeScriptVar(npc, SCRIPTVAR_CACHED_PATROL_PATH);
utils.removeScriptVar(npc, SCRIPTVAR_CACHED_PATROL_NAMED_PATH);
utils.removeScriptVar(npc, SCRIPTVAR_CACHED_PATROL_TYPE);
}
}
void resumePatrol( obj_id npc )
{
LOGC(aiLoggingEnabled(npc), "debug_ai", ("ai_lib::resumePatrol() self(" + npc + ") getName(" + getName(npc) + ")"));
if ( isIdValid(npc) && aiGetMovementState(npc) != MOVEMENT_PATROL && hasSuspendedMovement(npc) )
{
resumeMovement(npc);
}
}
boolean canPatrol( obj_id npc )
{
if ( isIdValid(npc) )
return utils.hasScriptVar(npc, SCRIPTVAR_CACHED_PATROL_TYPE);
return false;
}
location[] parseWaypoints(obj_id npc, string[] waypoints)
{
if ( !isIdValid(npc) || waypoints != null )
return null;
location baseLoc = aiGetHomeLocation( npc );
if ( (baseLoc.x == 0.0f) && (baseLoc.z == 0.0f) )
{
baseLoc = getLocation( npc );
if ( (baseLoc.x == 0.0f ) && (baseLoc.z == 0.0f) )
{
debugServerConsoleMsg( npc, "* ERROR: TRYING TO GET LOCATION ON AN NPC NOT INSTANTIATED! *" );
return null;
}
}
location[] patrolLocs = new location[waypoints.length];
location patrolLoc = new location( baseLoc );
for ( int i = 0; i < waypoints.length; i++ )
{
float[] coords = parseWaypoints( waypoints[i] );
if ( coords != null && coords.length == 2 )
{
patrolLoc.x = baseLoc.x + coords[0];
patrolLoc.z = baseLoc.z + coords[1];
}
else
debugServerConsoleMsg( npc, "* ERROR: COULD NOT PARSE WAYPOINT STRING <" + waypoints[i] + "> *" );
patrolLocs[i] = patrolLoc;
}
return patrolLocs;
}
float[] parseWaypoints(string text)
{
int intIndex = 0;
int intI = 0;
intIndex = text.indexOf(",");
string strText1 = "";
string strText2 = "";
if(intIndex<0)
{
return null;
}
else
{
while(intI < text.length() )
{
if (intI < intIndex )
strText1 = strText1+text.charAt(intI);
else if (intI > intIndex )
strText2 = strText2+text.charAt(intI);
intI = intI+1;
}
}
float[] returnCoords = new float[2];
returnCoords[0] = Float.parseFloat(strText1);
returnCoords[1] = Float.parseFloat(strText2);
return returnCoords;
}
void setIgnoreCombat( obj_id npc )
{
setWantSawAttackTriggers( npc, false );
}
/* -----------------8/12/2002 2:33PM-----------------
* ai.diction - This objvar specifies which npc reaction stringfile
* the npc should use to bark spam.
*
* If the objvar isn't set then the NPC won't speak.
* --------------------------------------------------*/
void barkString( obj_id npc, string text )
{
if ( !text.equals("death") )
{
if ( ai_lib.isAiDead( npc ) )
return;
}
if (!hasObjVar( npc, "ai.diction") )
return;
if ( utils.hasScriptVar( npc, "ai.recentlyBarked") )
{
if ( getGameTime() < utils.getIntScriptVar( npc, "ai.recentlyBarked"))
return;
}
if ( !ai_lib.isNpc( npc ) && !pet_lib.isDroidPet( npc ) )
{
removeObjVar( npc, "ai.diction" );
return;
}
//hmm. We should convert diction barks to be directed To a specific player,
// use prose packages to say the player's name, and do language checks
// for wookiees talking to players. That would be great.
if ( getSpecies (npc)==SPECIES_WOOKIEE )
{
removeObjVar( npc, "ai.diction" );
return;
}
utils.setScriptVar( npc, "ai.recentlyBarked", getGameTime()+rand(20,45) );
location loc = getLocation( npc );
if ( locations.isInCity( loc ) )
{
if ( rand(1,100) != 1 )
return;//1/100 chance to spam in town
}
else
{
if ( rand( 1,10) != 1 )
return;//1/10 chance to spam out of town
}
string diction = getStringObjVar( npc, "ai.diction" );
string stringFile = "npc_reaction/" + diction;
string textString = text + "_" + rand( 1, 16 );
string_id speakString = new string_id( stringFile, textString );
if ( getString(speakString) == null )
{
debugServerConsoleMsg( npc, "WARNING: Npc_reaction " + speakString + " - does it exist?" );
return;
}
//debugSpeakMsg( npc, stringFile + ":" + textString );
chat.chat( npc, speakString );
}
boolean isAnimal( obj_id npc )
{
return isMonster(npc);
}
boolean isMonster( obj_id npc )
{
int myNiche = aiGetNiche( npc );
if ( myNiche == NICHE_MONSTER ||
myNiche == NICHE_HERBIVORE ||
myNiche == NICHE_CARNIVORE ||
myNiche == NICHE_PREDATOR )
return true;
else
return false;
}
boolean isDroid (obj_id npc)
{
int niche = aiGetNiche(npc);
if ( niche == NICHE_DROID)
return true;
else
return false;
}//end isDroid
boolean isPredator (obj_id npc)
{
int niche = aiGetNiche(npc);
if (niche == NICHE_PREDATOR)
return true;
else
return false;
}//end isPredator
boolean isCarnivore (obj_id npc)
{
int niche = aiGetNiche(npc);
if (niche == NICHE_CARNIVORE)
return true;
else
return false;
}//end isCarnivore
boolean isHerbivore (obj_id npc)
{
int niche = aiGetNiche(npc);
if (niche == NICHE_HERBIVORE)
return true;
else
return false;
}//end isHerbivore
boolean isVehicle (obj_id npc)
{
int niche = aiGetNiche(npc);
if (niche == NICHE_VEHICLE)
return true;
else
return false;
}//end isVehicle
boolean isAndroid (obj_id npc)
{
int niche = aiGetNiche(npc);
if (niche == NICHE_ANDROID)
return true;
else
return false;
}//end isAndroid
boolean isHumanoid(obj_id target)
{
if (isPlayer(target))
return true;
else
{
int niche = aiGetNiche(target);
if (niche == NICHE_NPC || niche == NICHE_ANDROID)
return true;
}
return false;
}
boolean isNpc( obj_id npc )
{
int myNiche = aiGetNiche( npc );
return ( myNiche == NICHE_NPC );
}
boolean isTurret (obj_id npc)
{
int got = getGameObjectType(npc);
if ( isGameObjectTypeOf(got, GOT_installation_turret) )
return true;
else
return false;
}//end isTurret
void setIgnoreCombat(obj_id npc, boolean b)
{
setWantSawAttackTriggers( npc, b);
}
void setDefaultCalmBehavior( obj_id npc, int behavior )
{
LOGC(aiLoggingEnabled(npc), "debug_ai", "ai_lib::setDefaultCalmBehavior() self(" + npc + getName(npc) + ") behavior(" + behavior + ")");
if ( !isIdValid(npc) )
return;
if (behavior == BEHAVIOR_WANDER)
{
behavior = BEHAVIOR_LOITER;
}
setObjVar(npc, "ai.defaultCalmBehavior", behavior);
messageTo(npc, "handleSetDefaultBehavior", null, 1, false);
}
void greet(obj_id ai, obj_id player)
{
LOGC(aiLoggingEnabled(ai), "debug_ai", "ai_lib::greet() ai(" + ai + ":" + getName(ai) + ") player(" + player + ":" + getName(player) + ")");
if (isInCombat(ai))
return;
const int reaction = factions.getFactionReaction(ai, player);
if (reaction < factions.REACTION_NEUTRAL)
{
chat.setAngryMood(ai );
ai_lib.barkString(ai, "hi_mean");
}
else if (reaction > factions.REACTION_NEUTRAL)
{
chat.setGoodMood(ai);
ai_lib.barkString(ai, "hi_nice");
}
else
{
chat.setNeutralMood(ai);
ai_lib.barkString(ai, "hi_mid");
}
}
void dismiss(obj_id ai, obj_id player)
{
LOGC(aiLoggingEnabled(ai), "debug_ai", "ai_lib::dismiss() ai(" + ai + ":" + getName(ai) + ") player(" + player + ":" + getName(player) + ")");
if (isInCombat(ai))
return;
const int reaction = factions.getFactionReaction(ai, player);
if (reaction < factions.REACTION_NEUTRAL)
{
chat.setBadMood(ai);
ai_lib.barkString(ai, "bye_mean");
}
else if (reaction > factions.REACTION_NEUTRAL)
{
chat.setGoodMood(ai);
ai_lib.barkString(ai, "bye_nice");
}
else
{
chat.setNeutralMood(ai);
ai_lib.barkString(ai, "bye_mid");
}
}
//dupe of function call below because all the others start with aiIs, not isAi
boolean aiIsDead( obj_id npc )
{
return isAiDead( npc );
}
boolean isAiDead( obj_id npc )
{
if ( !isMob(npc) )
return (isDisabled(npc));
if ( isIncapacitated( npc ))
{
//debugSpeakMsg( npc, "i am incapacitated" );
return true;
}
if (isDead(npc))
{
//debugSpeakMsg( npc, "so I am dead" );
return true;
}
//debugSpeakMsg( npc, "so i am not dead" );
return false;
}
void aiFollow( obj_id npc, obj_id target )
{
aiFollow(npc, target, DEFAULT_FOLLOW_MIN, DEFAULT_FOLLOW_MAX);
}
void aiFollow(obj_id npc, obj_id target, float min_dist, float max_dist)
{
if(target == npc)
{
debugServerConsoleMsg( npc, npc + " was told to follow itself");
return;
}
if(getPosture( npc ) != POSTURE_UPRIGHT)
{
posture.stand(npc);
}
setObjVar(npc, "ai.persistantFollowing.target", target);
if(min_dist < 1f)
{
min_dist = 1f;
}
if(max_dist < 1f)
{
max_dist = 1f;
}
if(max_dist <= min_dist)
{
max_dist = min_dist + 1f;
}
setObjVar(npc, "ai.persistantFollowing.min_dist", min_dist);
setObjVar(npc, "ai.persistantFollowing.max_dist", max_dist);
follow(npc, target, min_dist, max_dist);
}
boolean isFollowing(obj_id npc)
{
if(!isIdValid(npc))
{
return false;
}
return hasObjVar(npc, "ai.persistantFollowing");
}
obj_id getFollowTarget(obj_id npc)
{
if(!isIdValid(npc))
{
return null;
}
return getObjIdObjVar(npc, "ai.persistantFollowing.target");
}
void resumeFollow(obj_id npc)
{
if(!isIdValid(npc))
return;
obj_id target = getObjIdObjVar(npc, "ai.persistantFollowing.target");
if(isIdValid(target))
{
float min_dist = DEFAULT_FOLLOW_MIN;
if(hasObjVar(npc, "ai.persistantFollowing.min_dist"))
{
min_dist = getFloatObjVar(npc, "ai.persistantFollowing.min_dist");
}
float max_dist = DEFAULT_FOLLOW_MAX;
if(hasObjVar(npc, "ai.persistantFollowing.max_dist"))
{
max_dist = getFloatObjVar(npc, "ai.persistantFollowing.max_dist");
}
aiFollow(npc, target, min_dist, max_dist);
return;
}
aiStopFollowing(npc);
}
void aiStopFollowing(obj_id npc)
{
stop(npc);
removeObjVar(npc, "ai.persistantFollowing");
if(getBehavior(npc) <= BEHAVIOR_CALM)
{
messageTo(npc, "resumeDefaultCalmBehavior", null, 5, false);
}
}
string getMood( obj_id npc )
{
if ( !hasObjVar( npc, "ai.mood" ) )
return ai_lib.MOOD_CALM;
else
return getStringObjVar( npc, "ai.mood" );
}
void pathNear( obj_id npc, location dest, float range )
{
location startLoc = getLocation( npc );
if ( dest.x < startLoc.x )
dest.x += range;
else
dest.x -= range;
if ( dest.z < startLoc.z )
dest.z += range;
else
dest.z -= range;
pathTo( npc, dest );
}
void followInFormation( obj_id npc, obj_id leader, int formationType, int position )
{
//debugSpeakMsg( npc, "following " + leader );
if ( npc == leader )
{
debugServerConsoleMsg( npc, npc + " was told to followInFormation itself" );
return;
}
setObjVar( npc, "ai.inFormation", leader );
setObjVar( npc, "ai.formationType", formationType );
setObjVar( npc, "ai.formationPosition", position );
if ( !isInCombat( npc ) )
{
stop( npc );
resumeFormationFollowing( npc );
}
}
void resumeFormationFollowing( obj_id npc )
{
//debugSpeakMsg( npc, "resuming following" );
if ( isInCombat( npc ))
return;
obj_id leader = getObjIdObjVar( npc, "ai.inFormation" );
if ( !exists( leader ) || !isInWorld( leader ) || isAiDead( leader ) )
{
removeObjVar( npc, "ai.inFormation" );
return;
}
int formationType = getIntObjVar( npc, "ai.formationType" );
int position = getIntObjVar( npc, "ai.formationPosition" );
switch ( formationType )
{
case FORMATION_WEDGE :
followInWedgeFormation( npc, leader, position );
break;
case FORMATION_LINE :
followInLineFormation( npc, leader, position );
break;
case FORMATION_BOX :
followInBoxFormation( npc, leader, position );
break;
default:
followInColumnFormation( npc, leader, position );
break;
}
}
void followInWedgeFormation( obj_id npc, obj_id leader, int position )
{
if ( npc == leader )
{
debugServerConsoleMsg( npc, npc + " was told to followInWedgeFormation itself" );
return;
}
// L = leader
//
// ^
// L
// 2 1
// 4 3
// 6 5
// ... ...
// Clamp the position to positive integers
position = Math.max(1, position);
location offset = new location();
const float spacing = getObjectCollisionRadius(leader) * 2.25f;
const float x = (spacing * (float)Math.ceil(position / 2.0f));
offset.x = (position % 2 == 0) ? -x : x;
offset.z = -x;
follow(npc, leader, offset);
}
void followInBoxFormation( obj_id npc, obj_id leader, int position )
{
if ( npc == leader )
{
debugServerConsoleMsg( npc, npc + " was told to followInLineFormation itself" );
return;
}
/* POSITIONS:
0 1 2
3 4
5 6 7
*/
location offset = new location(0,0,0,"");
//set the x:
if ( position < 3 )
{
offset.x += ( position * 3 );
}
else if ( position == 4 )
{
offset.x = 6;
}
else if ( position !=3 )
{
offset.x += ((position-5)*3);
}
//set the z:
if ( position == 3 || position == 4 )
{
offset.z += 3;
}
else if ( position > 4 )
{
offset.z += 6;
}
if ( position < 1 || position > 7 )
follow( npc, leader, rand(15,20), rand(10,18));
else
follow( npc, leader, offset );
}
void followInLineFormation( obj_id npc, obj_id leader, int position )
{
if ( npc == leader )
{
debugServerConsoleMsg( npc, npc + " was told to followInLineFormation itself" );
return;
}
// L = leader
//
// ^
// ... 6 4 2 L 1 3 5 ...
// Clamp the position to positive integers
position = Math.max(1, position);
location offset = new location();
const float spacing = getObjectCollisionRadius(leader) * 2.25f;
const float x = (spacing * (float)Math.ceil(position / 2.0f));
offset.x = (position % 2 == 0) ? -x : x;
follow(npc, leader, offset);
}
void followInColumnFormation( obj_id npc, obj_id leader, int position )
{
if ( npc == leader )
{
debugServerConsoleMsg( npc, npc + " was told to followInColumnFormation itself" );
return;
}
// L = leader
//
// ^
// L 1
// 2 3
// 4 5
// 6 7
// 8 9
// . .
// . .
// . .
// Clamp the position to positive integers
position = Math.max(1, position);
location offset = new location();
const float spacing = getObjectCollisionRadius(leader) * 2.25f;
offset.x = (position % 2 == 0) ? 0.0f : spacing;
offset.z = -(spacing * (float)Math.ceil((position - 1) / 2.0f));
follow(npc, leader, offset);
}
void pathAwayFrom( obj_id npc, obj_id target )
{
if ( !isIdValid( npc ) || !isIdValid( target ) )
{
return;
}
if ( npc == target )
{
return;
}
if ( hasObjVar( npc, "ai.pathingAwayFrom"))
{
obj_id oldTarget = getObjIdObjVar( npc, "ai.pathingAwayFrom" );
if ( oldTarget == target )
return;
if ( getDistance( npc, target ) > getDistance( npc, oldTarget ) )
return;
}
location myLoc = new location( getLocation( npc ) );
location targetLoc = new location( getLocation( target ) );
if ( myLoc.x < targetLoc.x )
myLoc.x -= rand( 20f, 40f );
else
myLoc.x += rand( 20f, 40f );
if ( myLoc.z < targetLoc.z )
myLoc.z -= rand( 20f, 40f );
else
myLoc.z += rand( 20f, 40f );
setObjVar( npc, "ai.pathingAwayFrom", target );
pathTo( npc, myLoc );
messageTo( npc, "handleClearPathingFlag", null, 30f, isObjectPersisted( npc ) );
}
void setLoiterRanges( obj_id npc, float minRange, float maxRange )
{
setObjVar( npc, "ai.loiterMinRange", minRange );
setObjVar( npc, "ai.loiterMaxRange", maxRange );
}
int aiGetSpecies( obj_id npc )
{
return getSpecies( npc );
}
void setCustomIdleAnimation( obj_id npc, string animationString )
{
setDefaultCalmMood( npc, animationString );
}
void setDefaultCalmMood( obj_id npc, string mood )
{
//debugSpeakMsg( npc, "setting the default calm mood objvar" );
setObjVar( npc, "ai.defaultCalmMood", mood );
if ( getBehavior(npc) <= BEHAVIOR_CALM )
{
//debugSpeakMsg( npc, "calm, so setting mood" );
setMood( npc, MOOD_CALM );
}
}
int getDefaultCalmBehavior(obj_id ai)
{
int behavior = BEHAVIOR_LOITER;
if (hasObjVar(ai, "ai.defaultCalmBehavior"))
{
behavior = getIntObjVar(ai, "ai.defaultCalmBehavior");
}
return behavior;
}
void aiPathTo( obj_id npc, location pathLoc )
{
if ( (pathLoc.x == 0.0f) && (pathLoc.z == 0.0f) )
{
//nope.
return;
}
setObjVar( npc, "ai.persistentPathing", pathLoc );
stop( npc );
pathTo( npc, pathLoc );
}
/*
int aiGetNiche( obj_id npc )
{
if ( isPlayer( npc ) )
return getNiche( npc );
string creatureName = getCreatureName( npc );
if ( creatureName != null )
{
int niche = dataTableGetInt( CREATURE_TABLE, creatureName, "niche" );
return niche;
}
int niche = getNiche( npc );
return niche;
}
*/
int aiGetNiche( obj_id npc )
{
if ( isPlayer( npc ) )
return NICHE_PC;
string creatureName = getCreatureName( npc );
if ( creatureName != null )
return ( dataTableGetInt( CREATURE_TABLE, creatureName, "niche" ) );
else
return NICHE_NONE;
}
int aiGetNiche( string creatureName )
{
if ( creatureName == null || creatureName.equals("") )
return NICHE_NONE;
return dataTableGetInt( CREATURE_TABLE, creatureName, "niche" );
}
string getSocialGroup( obj_id npc )
{
string creatureName = getCreatureName(npc);
if(creatureName != null || !beast_lib.isBeast(npc))
{
string socialGroup = dataTableGetString( CREATURE_TABLE, creatureName, "socialGroup" );
return socialGroup;
}
return null;
}
boolean isSameSocialGroup( obj_id npc, obj_id target )
{
boolean result = false;
if(!pet_lib.isPet(npc) && !pet_lib.isPet(target) && !beast_lib.isBeast(npc) && !beast_lib.isBeast(target))
{
const string npcCreatureName = getCreatureName(npc);
const string targetCreatureName = getCreatureName(target);
if (npcCreatureName != null && targetCreatureName != null)
{
string mySocialGroup = getSocialGroup(npc);
string yourSocialGroup = getSocialGroup(target);
if ( (mySocialGroup != null)
&& (yourSocialGroup != null)
&& mySocialGroup.equals(yourSocialGroup))
{
result = true;
}
}
else if ((factions.getFaction(npc) != null) && (factions.getFaction(target) != null))
{
string mySocialGroup = factions.getFaction(npc);
string yourSocialGroup = factions.getFaction(target);
if ( (mySocialGroup != null)
&& (yourSocialGroup != null)
&& mySocialGroup.equals(yourSocialGroup))
{
result = true;
}
}
}
return result;
}
boolean isHerdingCreature( obj_id npc )
{
// Do data checks on server load
if ( isNpc( npc ) || isPlayer( npc ) || isAndroid(npc))
return false;
string creatureName = getCreatureName( npc );
if ( creatureName != null )
{
boolean isHerding = (dataTableGetInt( CREATURE_TABLE, creatureName, "herd" )==1);
return isHerding;
}
return false;
}
boolean isStalkingCreature(obj_id ai)
{
// Do data checks on server load
if (isPlayer(ai) || (aiGetNiche(ai) == NICHE_NPC) || isAndroid(ai))
return false;
if (hasScript(ai, "ai.pet_advance"))
return false;
return aiIsStalker(ai);
}
boolean isAggroToward( obj_id npc, obj_id threat )
{
if ( hasScript( npc, "ai.pet_advance" ) )
return false;
// If the threat has the npc on their PEF list and
// also does PVP faction checks
if ( pvpIsEnemy( npc, threat ) )
{
//debugSpeakMsg( npc, "we are enemies");
return true;
}
//creatures in the same social group aren't aggro:
if ( ai_lib.isSameSocialGroup( npc, threat ))
return false;
// In creatures_table.xml, remove references to NICHE_MONSTER and NICHE_PREDATOR
//players are considered to be aggro to creatures, not to npcs
//if ( isPlayer( npc ) )
//{
// //debugSpeakMsg( npc, "you are a player and I am a monster");
// return ( ai_lib.isMonster( threat ) );
//}
// Non-imperial/rebel faction
int reaction = factions.getFactionReaction( npc, threat );
if ( reaction == factions.REACTION_NEGATIVE )
{
//debugSpeakMsg( npc, "reaction is negative");
return true;
}
if (!ai_lib.isMonster( npc ) )
{
if ( ai_lib.isAggro( npc ) )
{
//I will attack you unless I like you very much:
if ( reaction <= factions.REACTION_NEUTRAL )
{
//debugSpeakMsg( npc, "reaction is worse than neutral");
return true;
}
}
return false;// all checks below are for CREATURES only
}
// NON-MONSTERS
//aggro creatures hate players:
if ( isPlayer( threat ) && ai_lib.isAggro( npc ) )
{
//debugSpeakMsg( npc, "you are a player and I am aggroo");
return true;
}
int npcNiche = ai_lib.aiGetNiche( npc );
int threatNiche = ai_lib.aiGetNiche( threat );
//Carnivores and Predators eat herbivores
if ( npcNiche == NICHE_CARNIVORE /* || npcNiche == NICHE_PREDATOR */)
{
if ( threatNiche == NICHE_HERBIVORE )
return true;
}
return false;
}
boolean isAggro(obj_id ai)
{
if (isPlayer(ai))
return false;
if ( hasScript( ai, "ai.pet_advance" ) )
return false;
if ( hasScript( ai, "systems.missions.dynamic.mission_bounty_target"))
return false;
return aiIsAggressive(ai);
}
boolean isHealingNpc( obj_id npc )
{
if ( isPlayer( npc ) )
return false;
int niche = aiGetNiche( npc );
if ( niche != NICHE_NPC || niche != NICHE_ANDROID)
return false;
string creatureName = getCreatureName( npc );
if ( creatureName != null )
{
boolean isHealer = (dataTableGetInt( CREATURE_TABLE, creatureName, "healer" )!=0);
return isHealer;
}
return false;
}
boolean incapacitateMob(obj_id target)
{
if ( target == null || !isMob(target) )
{
return false;
}
boolean result = true;
result &= setHealth(target, -50);
result &= setAction(target, -50);
result &= setMind(target, -50);
return result;
}
boolean isHumanSkeleton( obj_id npc )
{
if ( isPlayer(npc) )
return true;
int speciesNum = ai_lib.aiGetSpecies( npc );
if ( speciesNum == -1 )
{
return false;
}
string skeleton = dataTableGetString("datatables/ai/species.iff", speciesNum, "Skeleton");
if ( skeleton == "human" )
{
return true;
}
return false;
}
string getSkeleton(int speciesNum)
{
if ( speciesNum == -1 )
return null;
string skeleton = dataTableGetString("datatables/ai/species.iff", speciesNum, "Skeleton");
return skeleton;
}
string getSkeleton(obj_id npc)
{
int speciesNum = ai_lib.aiGetSpecies( npc );
LOG("mount", "speciesnum is "+speciesNum);
if ( speciesNum == -1 )
{
return null;
}
string skeleton = dataTableGetString("datatables/ai/species.iff", speciesNum, "Skeleton");
LOG("mount", "skeleton is "+skeleton);
return skeleton;
}
void doThreatenAnimation( obj_id npc )
{
if (ai_lib.aiGetNiche( npc )!=NICHE_NPC || !isAndroid(npc))
{
doAction( npc, ACTION_THREATEN );
return;
}
string anim = ai_lib.ACTION_THREATEN;
switch ( rand(0,13))
{
case 0 :
anim = ai_lib.ACTION_THREATEN;
break;
case 1 :
anim = "alert";
break;
case 2 :
anim = "angry";
break;
case 3 :
anim = "gesticulate_wildly";
break;
case 4 :
anim = "greet";
break;
case 5 :
anim = "look_casual";
break;
case 6 :
anim = "look_left";
break;
case 7 :
anim = "look_right";
break;
case 8 :
anim = "point_accusingly";
break;
case 9 :
anim = "pound_fist_chest";
break;
case 10 :
anim = "pound_fist_palm";
break;
case 11 :
anim = "taunt1";
break;
case 12 :
anim = "taunt2";
break;
case 13 :
anim = "taunt3";
break;
}
ai_lib.doAction( npc, anim );
}
void doVictoryDance( obj_id npc )
{
if (ai_lib.isMonster( npc ))
{
if ( rand(1,500)==1 )
{
if ( rand(1,2)==1 )
doAnimationAction( npc, "trick_1");
else
doAnimationAction( npc, "trick_2");
}
else
doAction( npc, "vocalize" );
return;
}
string anim = "celebrate";
switch ( rand(0,23))
{
case 0 :
anim = "celebrate";
break;
case 1 :
anim = "applause_excited";
break;
case 2 :
anim = "belly_laugh";
break;
case 3 :
anim = "celebrate1";
break;
case 4 :
anim = "coup_de_grace";
break;
case 5 :
anim = "dismiss";
break;
case 6 :
anim = "flex_biceps";
break;
case 7 :
anim = "laugh_pointing";
break;
case 8 :
anim = "point_accusingly";
break;
case 9 :
anim = "pound_fist_chest";
break;
case 10 :
anim = "pound_fist_palm";
break;
case 11 :
anim = "salute1";
break;
case 12 :
anim = "salute2";
break;
case 13 :
anim = "shrug_hands";
break;
case 14 :
anim = "shrug_shoulders";
break;
case 15 :
anim = "smack_self";
break;
case 16 :
anim = "shake_head_disgust";
break;
case 17 :
anim = "snap_finger1";
break;
case 18 :
anim = "snap_finger2";
break;
case 19 :
anim = "tap_head";
break;
case 20 :
anim = "taunt1";
break;
case 21 :
anim = "taunt2";
break;
case 22 :
anim = "taunt3";
break;
case 23 :
anim = "yawn";
break;
case 24 :
anim = "check_wrist_device";
break;
}
doAction( npc, anim );
}
obj_id getLair( obj_id npc )
{
if ( isPlayer(npc) )
return null;
//DO I know whether I have a lair or not?
if ( utils.hasScriptVar(npc, "ai.hasLair" ) )
return utils.getObjIdScriptVar(npc, "ai.hasLair" );
obj_id myPOI = getObjIdObjVar( npc, "poi.baseObject" );
if ( myPOI == null )
{
utils.setScriptVar( npc, "ai.noLiar", true );
return null;
}
string buildingType = getStringObjVar( myPOI, "spawning.buildingType" );
if ( (buildingType == null || buildingType.equals( "none" )) && !hasObjVar( myPOI, "spawning.target" ))
{
utils.setScriptVar( npc, "ai.noLair", true );
return null;
}
utils.setScriptVar( npc, "ai.hasLair", myPOI );
return myPOI;
}
int aiGetApproachTriggerRange( obj_id npc )
{
return (int)aiGetAggroRadius(npc);
}
void aiSetPosture( obj_id npc, int newPosture )
{
if ( ( getState( npc, STATE_COMBAT ) != 1 ) )
{
setPostureClientImmediate(npc, newPosture);
}
else
{
attacker_results cbtAnimationResults = new attacker_results();
cbtAnimationResults.endPosture = newPosture;
cbtAnimationResults.id = npc;
doCombatResults("change_posture", cbtAnimationResults, null);
}
}
boolean canSit( obj_id npc )
{
int speciesNum = ai_lib.aiGetSpecies( npc );
if ( speciesNum == -1 )
{
return false;
}
boolean hasSitAnims = ( dataTableGetInt("datatables/ai/species.iff", speciesNum, "CanSit") == 1 );
return hasSitAnims;
}
boolean canLieDown( obj_id npc )
{
int speciesNum = ai_lib.aiGetSpecies( npc );
if ( speciesNum == -1 )
{
return false;
}
boolean hasLayAnims = ( dataTableGetInt("datatables/ai/species.iff", speciesNum, "CanLieDown") == 1 );
return hasLayAnims;
}
boolean isInSameBuilding(obj_id npc, obj_id target)
{
if(!isIdValid(npc))
return false;
if(!isIdValid(target))
return false;
obj_id npcCell = getLocation( npc ).cell;
obj_id targetCell = getLocation( target ).cell;
if ( isIdValid( npcCell ) == false && isIdValid( targetCell ) == false )
return true;//we're both outside
else if ( isIdValid( npcCell ) == false || isIdValid( targetCell ) == false )
return false;//one of us is outside
obj_id npcBldg = getTopMostContainer( npc );
obj_id targetBldg = getTopMostContainer( target );
if ( npcBldg == targetBldg )
return (canSee( npc, target ));//we're in the same building (and can see each other)
else
return false;//not in the same bldg
}
string getAttackString( int hash )
{
string outstring = "@combat_effects:";
if ( hash == 0 )
return "@combat_effects:none";
int[] attacks = dataTableGetIntColumn( "datatables/ai/special_attack.iff", "ATTACK_HASH" );
string[] attackstrings = dataTableGetStringColumn( "datatables/ai/special_attack.iff", "ATTACK_STRING" );
for ( int i=0; i<attacks.length; i++ )
{
if ( hash == attacks[i] )
return "@combat_effects:"+attackstrings[i];
}
return "@combat_effects:unknown_attack";
}
string getMilkType( obj_id npc )
{
string creatureName = getCreatureName( npc );
if ( creatureName == null )
return null;//the default
else
return dataTableGetString( CREATURE_TABLE, creatureName, "milkType" );
}
/*
Straight chance to dump out based on player underworld skillset
*/
boolean checkForSmuggler(obj_id player)
{
//check to make sure player is smuggler
if (!hasSkill(player, "class_smuggler_phase1_novice"))
{
return false;
}
else
{
int evadeScan = 0;
if (hasSkill(player, "class_smuggler_phase1_novice"))
evadeScan = evadeScan + 15;
if (hasSkill(player, "class_smuggler_phase2_03"))
evadeScan = evadeScan + 15;
if (hasSkill(player, "class_smuggler_phase2_novice"))
evadeScan = evadeScan + 15;
if (hasSkill(player, "class_smuggler_phase3_novice"))
evadeScan = evadeScan + 15;
if (hasSkill(player, "class_smuggler_phase4_novice"))
evadeScan = evadeScan + 15;
if (hasSkill(player, "class_smuggler_phase4_master"))
evadeScan = evadeScan + 20;
int roll = rand(1,100);
//debugSpeakMsg(player, "Your Smuggler Evasion Score is: " + evadeScan);
//debugSpeakMsg(player, "The Scan Roll was: " + roll);
if (roll > evadeScan)
{
//smuggler is busted
sendSystemMessage(player, SMUGGLER_SCAN_FAIL);
return false;
}
}
//smuggler avoids being caught
sendSystemMessage(player, SMUGGLER_SCAN_SUCCESS);
return true;
}//end checkForSmuggler
//jedi check for contraband searches
boolean checkForJedi( obj_id player )
{
if ( !isJedi(player) || isJediState( player, JEDI_STATE_FORCE_SENSITIVE ) )
return false;
int mindTrick = 0;
if ( isJediState( player, JEDI_STATE_JEDI ) )
mindTrick += 40;
if ( isJediState( player, JEDI_STATE_FORCE_RANKED_LIGHT ) || isJediState( player, JEDI_STATE_FORCE_RANKED_DARK ) )
mindTrick += 20;
int roll = rand( 1, 100 );
if ( roll > mindTrick )
{
return false;
}
return true;
}
boolean setupNpc(obj_id npc, boolean conversable, boolean invulnerable)
{
return setupNpc(npc, null, conversable, invulnerable);
}
boolean setupNpc(obj_id npc, string name, boolean conversable, boolean invulnerable)
{
if (name != null && !name.equals(""))
setName(npc, name);
if (conversable)
setCondition(npc, CONDITION_CONVERSABLE);
setInvulnerable (npc, invulnerable);
return true;
}
void establishAgroLink(obj_id subject, float range)
{
string socialGroup = getSocialGroup(subject);
obj_id[] creatures = getCreaturesInRange(subject, range);
if (creatures == null || creatures.length == 0)
return;
resizeable obj_id[] linkedCreatures = new obj_id[0];
for (int i=0;i<creatures.length;i++)
{
if (getSocialGroup(creatures[i]).equals(socialGroup))
{
utils.addElement(linkedCreatures, creatures[i]);
}
}
if (linkedCreatures.length == 0)
return;
obj_id[] creatureList = linkedCreatures;
if (creatureList == null || creatureList.length == 0)
return;
utils.setScriptVar(subject, ALLY_LIST, creatureList);
for (int k=0;k<creatureList.length;k++)
{
utils.setScriptVar(subject, ALLY_LIST, creatureList);
}
}
void establishAgroLink(obj_id subject, obj_id[] allies)
{
if (allies == null || allies.length == 0)
return;
utils.setScriptVar(subject, ALLY_LIST, allies);
for (int i=0;i<allies.length;i++)
{
utils.setScriptVar(allies[i], ALLY_LIST, allies);
}
}
void triggerAgroLinks(obj_id subject, obj_id attacker)
{
if (!utils.hasScriptVar(subject, ALLY_LIST))
return;
obj_id[] allyList = utils.getObjIdArrayScriptVar(subject, ALLY_LIST);
if (allyList == null || allyList.length == 0)
return;
for (int i=0;i<allyList.length;i++)
{
if (isIdValid(allyList[i]) && exists(allyList[i]) && !isDead(allyList[i]))
{
if(!isInCombat(allyList[i]))
{
startCombat(allyList[i], attacker);
}
else
{
addHate(allyList[i], attacker, 1);
}
}
}
}
void creatureLevelUp(obj_id creature, obj_id victim)
{
showFlyText(creature, new string_id("cbt_spam", "level_up"), 2.5f, colors.CORNFLOWERBLUE);
playClientEffectObj(victim, "clienteffect/level_granted.cef", creature, null);
string creatureName = getCreatureName(creature);
if ( creatureName.indexOf( "elite_" ) < 1 && creatureName.indexOf( "boss_" ) < 1)
{
dictionary creatureDict = utils.dataTableGetRow( CREATURE_TABLE, creatureName );
create.initializeCreature( creature, creatureName, creatureDict, getLevel(creature)+1 );
}
return ;
}
boolean mindTrick(obj_id player, obj_id target)
{
int niche = aiGetNiche(target);
if (vehicle.isVehicle(target) || niche == NICHE_DROID || niche == NICHE_ANDROID || niche == NICHE_VEHICLE || isTurret(target))
return false;
if (!isPlayer(target) && isOnHateList(player, target))
{
int mt_resist = getEnhancedSkillStatisticModifierUncapped(target, "resistance_mind_trick");
if (mt_resist >= 100)
{
showFlyTextPrivate(target, player, new string_id("cbt_spam", "immune"), 1.5f, colors.WHITE);
return false;
}
if (rand(1, 100) > mt_resist)
{
playClientEffectObj(target, "appearance/pt_mind_trick.prt", target, "root");
removeHateTarget(target, player);
return true;
}
else
{
showFlyTextPrivate(target, player, new string_id("cbt_spam", "resist"), 1.5f, colors.WHITE);
return false;
}
}
return false;
}
boolean isTauntable(obj_id creature)
{
return !utils.hasScriptVar(creature, "combat.immune.taunt");
}
void establishSharedHealth(resizeable obj_id[] allies)
{
for (int i=0;i<allies.length;i++)
{
utils.setScriptVar(allies[i], SHARED_HEALTH_LIST, allies);
}
}
int triggerSharedHealthLink(obj_id self, int totalDamage)
{
if (utils.hasScriptVar(self, ai_lib.SHARED_HEALTH_LIST))
{
resizeable obj_id[] allies = utils.getResizeableObjIdArrayScriptVar(self, ai_lib.SHARED_HEALTH_LIST);
utils.removeScriptVar(self, ai_lib.SHARED_HEALTH_LIST);
resizeable obj_id[] validList = new obj_id[0];
if (allies == null || allies.length == 0)
return totalDamage;
for(int q=0;q<allies.length;q++)
{
if (!isIdValid(allies[q]) || !exists(allies[q]) || isDead(allies[q]) || aiIsTethered(allies[q]))
continue;
validList.add(allies[q]);
}
utils.setScriptVar(self, ai_lib.SHARED_HEALTH_LIST, validList);
if(validList.length < 2)
{
return totalDamage;
}
int divisor = validList.length;
int split = Math.round((float)totalDamage / (float)divisor);
for(int k=0;k<validList.length;k++)
{
if (validList[k] == self)
continue;
damage(validList[k], DAMAGE_ELEMENTAL_HEAT, HIT_LOCATION_BODY, split);
}
return split;
}
return totalDamage;
}
int getDifficultyClass(obj_id target)
{
if (!isIdValid(target) || !exists(target) || !hasObjVar(target, "difficultyClass"))
return -1;
return getIntObjVar(target, "difficultyClass");
}
boolean isVehicleMine(obj_id self)
{
return hasScript(self, "theme_park.heroic.echo_base.vehicle_mine");
}