mirror of
https://github.com/SWG-Source/dsrc.git
synced 2026-07-31 00:15:54 -04:00
420 lines
13 KiB
Plaintext
420 lines
13 KiB
Plaintext
include library.utils;
|
|
include library.combat;
|
|
include library.static_item;
|
|
include library.colors;
|
|
include library.buff;
|
|
include library.vehicle;
|
|
|
|
const string CYBERNETICS_TABLE = "datatables/cybernetic/cybernetic.iff";
|
|
const string PROC_TABLE = "datatables/proc/proc.iff";
|
|
|
|
const string REAC_BASE = "reactive_proc.";
|
|
|
|
|
|
|
|
void executeProcEffects( obj_id attacker, obj_id defender)
|
|
{
|
|
executeProcEffects(attacker, defender, null);
|
|
}
|
|
|
|
void executeProcEffects( obj_id attacker, obj_id defender, combat_data actionData)
|
|
{
|
|
weapon_data weaponData = getWeaponData(getCurrentWeapon(attacker));
|
|
string params = "";
|
|
|
|
prose_package pp = new prose_package();
|
|
|
|
if(actionData != null)
|
|
{
|
|
if(actionData.params != null && !actionData.params.equals(""))
|
|
params == actionData.params;
|
|
}
|
|
|
|
if(!isMob(attacker))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(vehicle.isRidingVehicle(attacker))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (utils.hasScriptVar( attacker, "currentProcList" ) )
|
|
{
|
|
|
|
// Offensive AOE damage should not fire procs.
|
|
if(actionData.attackType == combat.CONE || actionData.attackType == combat.AREA || actionData.attackType == combat.TARGET_AREA)
|
|
{
|
|
return;
|
|
}
|
|
|
|
resizeable string[] procEffects = utils.getResizeableStringArrayScriptVar( attacker, "currentProcList" );
|
|
|
|
if ( procEffects != null && procEffects.length > 0 )
|
|
{
|
|
for ( int i = 0; i < procEffects.length; ++i )
|
|
{
|
|
dictionary parms = dataTableGetRow(PROC_TABLE, procEffects[i] );
|
|
if ( parms != null )
|
|
{
|
|
int procChance = parms.getInt( "procChance" );
|
|
//LOG("proc", "Proc: Inital Chance " +procChance);
|
|
|
|
int expertiseProcChance = (int)getSkillStatisticModifier(attacker, procEffects[i]);
|
|
|
|
// If you can spend points to raise the chance through expertise, use that percent chance instead.
|
|
if(expertiseProcChance > 0)
|
|
{
|
|
procChance = expertiseProcChance;
|
|
|
|
// If the expertise uses a kill meter, then get the kill meter's value and multiply it by the chance.
|
|
if(procEffects[i].startsWith("kill_meter_"))
|
|
{
|
|
procChance *= getKillMeter(attacker);
|
|
}
|
|
}
|
|
//LOG("proc", "Proc: Expertise Proc Chance "+procChance);
|
|
|
|
string noSelfProcBuffs = parms.getString( "noSelfProcBuffs" );
|
|
string noTargetProcBuffs = parms.getString( "noTargetProcBuffs" );
|
|
|
|
if(isGod(attacker) || isGod(defender))
|
|
LOG("expertise", "Proc: " + parms.getString("procString") + " noSelfProcBuffs: " + noSelfProcBuffs + " noTargetProcBuffs: " + noTargetProcBuffs);
|
|
|
|
// Never proc if the proc should cast a buff that already exists on the source of the proc or the target
|
|
if(buff.hasAnyBuffInList(attacker, noSelfProcBuffs) || buff.hasAnyBuffInList(defender, noTargetProcBuffs))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
string requiredBuffs = parms.getString( "requiredSelfBuffs" );
|
|
|
|
//if(isGod(attacker) || isGod(defender))
|
|
//LOG("expertise", "Proc: " + parms.getString("procString") + " requiredBuffs: " + requiredBuffs);
|
|
|
|
// Never proc if the buff required to proc is not on the source of the proc
|
|
if(requiredBuffs.length() > 0 && !buff.hasAnyBuffInList(attacker, requiredBuffs))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
|
|
//Attempt to normalize the procs. Some weapons fire more often than others, so we need to lower thier chances
|
|
if (procChance != 100)
|
|
procChance = Math.round(weaponData.attackSpeed * (float)procChance);
|
|
//LOG("proc", "Proc:Adjusted Proc Chance " + adjustedProcChance);
|
|
//LOG("proc", "Proc:Int Adjusted Proc Chance " + ((int)adjustedProcChance));
|
|
|
|
//if(isGod(attacker) || isGod(defender))
|
|
//LOG("expertise", "Proc: " + parms.getString("procString") + " Chance: " + procChance + " adjustedProcChance: " + adjustedProcChance);
|
|
|
|
if ( rand(0,99) < procChance )
|
|
{
|
|
string procCommand = parms.getString( "procString" );
|
|
if (procCommand != null)
|
|
{
|
|
if(combat.canUseWeaponWithAbility(attacker, weaponData, procCommand, false))
|
|
{
|
|
queueCommand(attacker, getStringCrc(procCommand.toLowerCase()), defender, params, COMMAND_PRIORITY_DEFAULT);
|
|
pp = prose.setStringId(pp, new string_id("proc/proc", procCommand));
|
|
showFlyTextPrivateProseWithFlags(attacker, attacker, pp, 1.5f, colors.LEMONCHIFFON, FLY_TEXT_FLAG_IS_CRITICAL_HIT );
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if(!isMob(defender))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(vehicle.isRidingVehicle(defender))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (utils.hasScriptVar( defender, "currentReacList" ) )
|
|
{
|
|
resizeable string[] reacEffects = utils.getResizeableStringArrayScriptVar( defender, "currentReacList" );
|
|
if ( reacEffects != null && reacEffects.length > 0 )
|
|
{
|
|
for ( int i = 0; i < reacEffects.length; ++i )
|
|
{
|
|
dictionary reacParms = dataTableGetRow(PROC_TABLE, reacEffects[i] );
|
|
if ( reacParms != null )
|
|
{
|
|
int reacChance = reacParms.getInt( "procChance" );
|
|
|
|
int expertiseReacChance = (int)getSkillStatisticModifier(defender, reacEffects[i]);
|
|
|
|
// If you can spend points to raise the chance through expertise, use that percent chance instead.
|
|
if(expertiseReacChance > 0)
|
|
{
|
|
reacChance = expertiseReacChance;
|
|
|
|
// If the expertise uses a kill meter, then get the kill meter's value and multiply it by the chance.
|
|
if(reacEffects[i].startsWith("kill_meter_"))
|
|
{
|
|
reacChance *= getKillMeter(defender);
|
|
}
|
|
}
|
|
|
|
string noSelfProcBuffs = reacParms.getString( "noSelfProcBuffs" );
|
|
string noTargetProcBuffs = reacParms.getString( "noTargetProcBuffs" );
|
|
|
|
// Never proc if the proc should cast a buff that already exists on the source of the proc or the target
|
|
if(buff.hasAnyBuffInList(defender, noSelfProcBuffs) || buff.hasAnyBuffInList(attacker, noTargetProcBuffs))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (reacChance != 100)
|
|
reacChance = Math.round(weaponData.attackSpeed * (float)reacChance);
|
|
|
|
if ( rand(0,99) < reacChance )
|
|
{
|
|
string reacCommand = reacParms.getString( "procString" );
|
|
|
|
if (reacCommand != null)
|
|
{
|
|
combat_data abilityData = combat_engine.getCombatData(reacCommand);
|
|
string cooldownGroup = abilityData.cooldownGroup;
|
|
float cooldownTime = abilityData.cooldownTime;
|
|
boolean canProc = false;
|
|
int timeLapse = -1;
|
|
|
|
if (utils.hasScriptVar(defender, REAC_BASE + cooldownGroup))
|
|
{
|
|
int lastProc = utils.getIntScriptVar(defender, REAC_BASE+cooldownGroup);
|
|
timeLapse = getGameTime() - lastProc;
|
|
|
|
if (timeLapse >= cooldownTime)
|
|
canProc = true;
|
|
}
|
|
else
|
|
{
|
|
canProc = true;
|
|
}
|
|
|
|
|
|
if (canProc)
|
|
{
|
|
if (queueCommand(defender, getStringCrc(reacCommand.toLowerCase()), attacker, "", COMMAND_PRIORITY_DEFAULT))
|
|
{
|
|
LOG("procCommand", "Reac -- " + reacCommand + " activated");
|
|
utils.setScriptVar(defender, REAC_BASE + cooldownGroup, getGameTime());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//This function builds a string array that is stored as a script var, 'currentProcList'
|
|
//This array contains a list of procs that are currently accessible and valid for the player
|
|
//Sources for procs are weapons, cybernetics, buffs, and expertise
|
|
void buildCurrentProcList( obj_id player )
|
|
{
|
|
// LOG("procCommand","checking for active procs");
|
|
resizeable string [] currentProcList = new string[0];
|
|
|
|
//Check for procs on the weapon equipped
|
|
obj_id weapon = getCurrentWeapon(player);
|
|
if(static_item.isStaticItem(weapon))
|
|
{
|
|
dictionary itemData = static_item.getStaticItemWeaponDictionary(weapon);
|
|
string procEffect = itemData.getString("proc_effect");
|
|
if (procEffect != null && procEffect !="")
|
|
{
|
|
string[] weaponProcEffects = split(procEffect, ',');
|
|
for ( int i = 0; i < weaponProcEffects.length; ++i )
|
|
currentProcList.addElement(weaponProcEffects[i]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//get the objvar from the weapon
|
|
if (hasObjVar(weapon, "procEffect"))
|
|
{
|
|
string[] weaponProcEffects = getStringArrayObjVar(weapon, "procEffect");
|
|
for ( int i = 0; i < weaponProcEffects.length; ++i )
|
|
currentProcList.addElement(weaponProcEffects[i]);
|
|
}
|
|
}
|
|
|
|
//Check for procs on buffs
|
|
if (utils.hasScriptVar( player, "procBuffEffects" ) )
|
|
{
|
|
string[] buffProcEffects = utils.getStringArrayScriptVar( player, "procBuffEffects" );
|
|
for ( int i = 0; i < buffProcEffects.length; ++i )
|
|
currentProcList.addElement(buffProcEffects[i]);
|
|
}
|
|
|
|
//Check for procs on cybernetics
|
|
if (utils.hasScriptVar( player, "cyberneticItems" ) )
|
|
{
|
|
string[] installedCybernetics = utils.getStringArrayScriptVar( player, "cyberneticItems" );
|
|
string procString = null;
|
|
|
|
for ( int i = 0; i < installedCybernetics.length; ++i )
|
|
{
|
|
procString = dataTableGetString(CYBERNETICS_TABLE, installedCybernetics[i], "procEffectString" );
|
|
if ( procString != null && procString != "" )
|
|
currentProcList.addElement(procString);
|
|
procString = null;
|
|
}
|
|
}
|
|
|
|
//Check for procs in the expertise proc/reactive script var
|
|
if (utils.hasScriptVar( player, "expertiseProcReacList" ) )
|
|
{
|
|
resizeable string[] expertiseList = utils.getResizeableStringArrayScriptVar( player, "expertiseProcReacList" );
|
|
for ( int i = 0; i < expertiseList.length; ++i )
|
|
if (expertiseList[i].endsWith("_proc"))
|
|
currentProcList.addElement(expertiseList[i]);
|
|
}
|
|
|
|
//Finish, since we roll for everything in your proclist we need to disallow multiple entries of the same type for offensive procs
|
|
//This means you are limited to 1 proc per unique proc type even if it is on multiple pieces of gear/buffs,etc
|
|
if(currentProcList.length > 0)
|
|
{
|
|
//make a temp list
|
|
resizeable string [] tempProcList = new string[0];
|
|
|
|
for ( int i = 0; i < currentProcList.length; ++i )
|
|
{
|
|
//only add unique procnames to the new temp list
|
|
if( !tempProcList.contains(currentProcList[i]) )
|
|
tempProcList.addElement(currentProcList[i]);
|
|
//LOG("proc", "List " + i +") " + currentProcList[i]);
|
|
}
|
|
//set the proclist on the player
|
|
utils.setScriptVar(player, "currentProcList", tempProcList);
|
|
}
|
|
else
|
|
if (utils.hasScriptVar( player, "currentProcList" ) )
|
|
utils.removeScriptVar(player, "currentProcList");
|
|
}
|
|
|
|
//This function builds a string array that is stored as a script var, 'currentReacList'
|
|
//This array contains a list of reactives that are currently accessible and valid for the player
|
|
//Sources for reactives are wearables, cybernetics, buffs, and expertise
|
|
void buildCurrentReacList( obj_id player )
|
|
{
|
|
// LOG("procCommand","checking for active reacs");
|
|
resizeable string [] currentReacList = new string[0];
|
|
|
|
//Check for procs on the wearables equipped
|
|
const string strWear[] = {
|
|
"chest2",
|
|
"chest1",
|
|
"hat",
|
|
"bicep_r",
|
|
"bicep_l",
|
|
"bracer_upper_r",
|
|
"bracer_upper_l",
|
|
"pants2",
|
|
"pants1",
|
|
"bandolier",
|
|
"wrist_r",
|
|
"wrist_l",
|
|
"gloves",
|
|
"ring_r",
|
|
"ring_l",
|
|
"utility_belt",
|
|
"shoes"
|
|
|
|
};
|
|
|
|
for(int intI = 0; intI < strWear.length; intI++)
|
|
{
|
|
|
|
obj_id wearable = getObjectInSlot(player, strWear[intI]);
|
|
if (!isIdNull(wearable))
|
|
{
|
|
if(static_item.isStaticItem(wearable))
|
|
{
|
|
//need to check whether it exists on the armor table or the item table
|
|
dictionary wearableData = null;
|
|
string wearableName = static_item.getStaticItemName(wearable);
|
|
if (static_item.getStaticObjectType(wearableName) == 2)
|
|
wearableData = static_item.getStaticArmorDictionary(wearable);
|
|
else wearableData = static_item.getStaticItemDictionary(wearable);
|
|
|
|
if (wearableData != null)
|
|
{
|
|
string reacEffect = wearableData.getString("reactive_effect");
|
|
if (reacEffect != null && reacEffect !="")
|
|
{
|
|
string [] wearableReacEffects = split(reacEffect, ',');
|
|
for ( int i = 0; i < wearableReacEffects.length; ++i )
|
|
{
|
|
currentReacList.addElement(wearableReacEffects[i]);
|
|
// LOG("procCommand", "Worn reactive found: " + wearableReacEffects[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//Check for reacs on buffs
|
|
if (utils.hasScriptVar( player, "reacBuffEffects" ) )
|
|
{
|
|
string[] buffReacEffects = utils.getStringArrayScriptVar( player, "reacBuffEffects" );
|
|
for ( int i = 0; i < buffReacEffects.length; ++i )
|
|
currentReacList.addElement(buffReacEffects[i]);
|
|
}
|
|
|
|
//Check for reacs on cybernetics
|
|
if (utils.hasScriptVar( player, "cyberneticItems" ) )
|
|
{
|
|
string[] installedCybernetics = utils.getStringArrayScriptVar( player, "cyberneticItems" );
|
|
string reacString = null;
|
|
|
|
for ( int i = 0; i < installedCybernetics.length; ++i )
|
|
{
|
|
reacString = dataTableGetString(CYBERNETICS_TABLE, installedCybernetics[i], "reacEffectString" );
|
|
if ( reacString != null && reacString != "" )
|
|
currentReacList.addElement(reacString);
|
|
reacString = null;
|
|
}
|
|
}
|
|
|
|
//Check for reacs in the expertise proc/reactive script var
|
|
if (utils.hasScriptVar( player, "expertiseProcReacList" ) )
|
|
{
|
|
resizeable string[] expertiseList = utils.getResizeableStringArrayScriptVar( player, "expertiseProcReacList" );
|
|
|
|
for ( int i = 0; i < expertiseList.length; ++i )
|
|
if (expertiseList[i].endsWith("_reac"))
|
|
{
|
|
// LOG("procCommand","Attempting to add " + expertiseList[i] + " as an expertise reac.");
|
|
currentReacList.addElement(expertiseList[i]);
|
|
}
|
|
}
|
|
|
|
if(currentReacList.length > 0)
|
|
{
|
|
// LOG("procCommand", "Reac List---");
|
|
// for ( int i = 0; i < currentReacList.length; ++i )
|
|
// LOG("procCommand", "List " + i +") " + currentReacList[i]);
|
|
|
|
utils.setScriptVar(player, "currentReacList", currentReacList);
|
|
}
|
|
else
|
|
if (utils.hasScriptVar( player, "currentReacList" ) )
|
|
utils.removeScriptVar(player, "currentReacList");
|
|
|
|
} |