mirror of
https://github.com/SWG-Source/dsrc.git
synced 2026-01-17 00:05:07 -05:00
3554 lines
146 KiB
Java
Executable File
3554 lines
146 KiB
Java
Executable File
package script.library;
|
|
|
|
import script.combat_engine.combat_data;
|
|
import script.*;
|
|
|
|
import java.util.Vector;
|
|
|
|
public class stealth extends script.base_script
|
|
{
|
|
public stealth()
|
|
{
|
|
}
|
|
public static final java.text.NumberFormat floatFormat = new java.text.DecimalFormat("###.##");
|
|
public static final int MAX_BUILDINGS_FOR_WILDNERNESS = 5;
|
|
public static final int MIN_BLENDIN_CROWD_SIZE = 10;
|
|
public static final String CAMO_KIT_ID = "camoKit";
|
|
public static final String ACTIVE_HEP = "active_hep";
|
|
public static final int MIN_MOVEMENT_PRIORITY = 3;
|
|
public static final int MIN_POSTURE_CHANGE_PRIORITY = 4;
|
|
public static final String INVIS_BREAK_RADIUS_FAR = "invis_break_far";
|
|
public static final String INVIS_BREAK_RADIUS_NEAR = "invis_break__near";
|
|
public static final String INVIS_UPKEEP_MSG_DISPATCHED = "invis_upkeep_dispatched";
|
|
public static final String TRAP_PROXIMITY_VOLUME = "trap_proximity";
|
|
public static final String SENSOR_PROXIMITY_VOLUME = "sensor_proximity";
|
|
public static final float INVIS_BREAK_MAX_FAR_DISTANCE = 20f;
|
|
public static final float INVIS_BREAK_NEAR_DISTANCE = 8f;
|
|
public static final int PASSIVE_BREACH_FAR = 2;
|
|
public static final int PASSIVE_BREACH_NEAR = 1;
|
|
public static final float PASSIVE_DETECT_CHANCE_FAR = 15.0f;
|
|
public static final float PASSIVE_DETECT_CHANCE_NEAR = 45.0f;
|
|
public static final float PASSIVE_DETECT_CHANCE_MOB = 20.0f;
|
|
public static final String INCOGNITO_OLD_FACTION = "stealth.incognitoFaction";
|
|
public static final float MIN_CHANCE_TO_DETECT_HIDDEN = 1f;
|
|
public static final float MAX_CHANCE_TO_DETECT_HIDDEN = 99f;
|
|
public static final float PASSIVE_DETECT_CHANCE = 20f;
|
|
public static final float ACTIVE_DETECT_CHANCE = 50f;
|
|
public static final float MAX_HIDING_DETECT_SCORE = 220;
|
|
public static final int HEP_UPKEEP_COST = 10;
|
|
public static final String HEP_BASE_POWER = "basePower";
|
|
public static final String HEP_EFFECTIVENESS = "effectiveness";
|
|
public static final int STEAL_NOTHING = 0;
|
|
public static final int STEAL_CREDITS = 1;
|
|
public static final int STEAL_LOOT = 2;
|
|
public static final int STEAL_TEMPLATE = 4;
|
|
public static final int STEAL_MARKED_ITEMS = 8;
|
|
public static final int STEAL_STEALING_TABLE = 16;
|
|
public static final float STEAL_LOOT_CHANCE_MOD = -0.90f;
|
|
public static final int STEAL_FAIL_CHANCE = 50;
|
|
public static final int STEAL_REGULAR_ITEM = 75;
|
|
public static final int STEAL_RARE_ITEM = 98;
|
|
public static final String STEAL_TYPE = "stealing.type";
|
|
public static final String STEAL_TEMPLATE_ITEMS = "stealing.availableLoot";
|
|
public static final String STEAL_ITEM_IS_STEALABLE = "stealing.isStealable";
|
|
public static final String TRAP_TR_ACCURACY = "trap.accuracy";
|
|
public static final String TRAP_POWER = "trap.power";
|
|
public static final String TRIGGER_TYPE = "trap.triggerType";
|
|
public static final String TRAP_TYPE = "trap.trapType";
|
|
public static final String TIMER_TIME = "trap.detonateTime";
|
|
public static final String PROXIMITY_RANGE = "trap.proximityRange";
|
|
public static final String TRAP_TRIGGER_ID = "trap.triggerId";
|
|
public static final String TRAP_MY_TRAP = "trap.myTrap";
|
|
public static final String TRAP_MY_PROXIMITY_TRIGGER = "trap.myTrap";
|
|
public static final String TRAP_FACTION = "trap.faction";
|
|
public static final String TRAP_PVP_TYPE = "trap.pvpType";
|
|
public static final String TRAP_DIFFICULTY = "trap.difficulty";
|
|
public static final String TRAP_FREQUENCY = "trap.frequency";
|
|
public static final String TRAP_GROUP = "trap.groupObject";
|
|
public static final String DETECT_EFFECTIVENESS = "trap.detect.effectiveness";
|
|
public static final String CONCEALABLE_DEVICE = "concealable";
|
|
public static final String CONCEALED_OBJECT = "isObjectConcealed";
|
|
public static final String CAMO_SKILL = "camouflageSkill";
|
|
public static final String DETECT_ATTEMPTS = "detectAttempts";
|
|
public static final String DETECT_TIMES = "detectTimes";
|
|
public static final String CAMOUFLAGED_AT_LEVEL = "camouflagedAtLevel";
|
|
public static final String TRAP_LEVEL = "levelOfTrap";
|
|
public static final String BIO_PROBE_TARGET_NAME = "trap.targetName";
|
|
public static final String BIO_PROBE_TRAP_TARGET = "trap.probeTarget";
|
|
public static final String BIO_PROBE_DECAYED = "probe.decayed";
|
|
public static final String BIO_PROBE_SAMPLE_TIME = "probe.sampleTime";
|
|
public static final String BIO_PROBE_STORAGE_TIME = "probe.storageTime";
|
|
public static final String BEACON_BATTERY = "beacon.battery";
|
|
public static final String BEACON_LOCATION = "beacon.location";
|
|
public static final String BEACON_TARGET = "beacon.target";
|
|
public static final String BEACON_TARGET_NAME = "beacon.targetName";
|
|
public static final String BEACON_MSG_DISPATCHED = "beacon.msgDispatched";
|
|
public static final String BEACON_SHUTDOWN_PENDING = "beacon.shutdownPending";
|
|
public static final String BEACON_LAST_KNOWN_LOC = "beacon.lastKnownLoc";
|
|
public static final String BEACON_LAST_KNOWN_TARGET_NAME = "beacon.lastKnownTargetName";
|
|
public static final String BEACON_LAST_KNOWN_TARGET = "beacon.lastKnownTarget";
|
|
public static final String SENSOR_ARMED_TIME = "sensor.armedTime";
|
|
public static final String BUFF_NO_BREAK_INVIS = "no_break_invis";
|
|
public static final float SENSOR_RANGE = 10f;
|
|
public static final float BEACON_INTERVAL = 20f;
|
|
public static final int TRIGGER_TYPE_TIMER = 1;
|
|
public static final int TRIGGER_TYPE_REMOTE = 2;
|
|
public static final int TRIGGER_TYPE_PROXIMITY = 3;
|
|
public static final int TRAP_CALTROP = 1;
|
|
public static final int TRAP_FLASHBANG = 2;
|
|
public static final int TRAP_HX2 = 3;
|
|
public static final int TRAP_KAMINODART = 4;
|
|
public static final int[] ALL_TRAP_TYPES = new int[]
|
|
{
|
|
TRAP_CALTROP,
|
|
TRAP_FLASHBANG,
|
|
TRAP_HX2,
|
|
TRAP_KAMINODART
|
|
};
|
|
public static final int[] ALL_TRIGGER_TYPES = new int[]
|
|
{
|
|
TRIGGER_TYPE_TIMER,
|
|
TRIGGER_TYPE_REMOTE,
|
|
TRIGGER_TYPE_PROXIMITY
|
|
};
|
|
public static final float TRAP_MIN_DISTANCE_BETWEEN = 10f;
|
|
public static final float TRAP_SELF_DESTRUCT_TIMEOUT = 60 * 10;
|
|
public static final float TRAP_HX2_BLAST_RADIUS = 15f;
|
|
public static final float TRAP_FLASHBANG_BLAST_RADIUS = 20f;
|
|
public static final float TRAP_CALTROP_BLAST_RADIUS = 10f;
|
|
public static final float TRAP_KAMINODART_BLAST_RADIUS = 10f;
|
|
public static final float KAMINODART_MAX_DURATION = 30;
|
|
public static final float KAMINODART_MAX_POTENCY = 175;
|
|
public static final float KAMINODART_MAX_STRENGTH = 175;
|
|
public static final int CALTROP_MAX_SNARE = 65;
|
|
public static final int CALTROP_MAX_DURATION = 30;
|
|
public static final int FLASHBANG_MAX_COMBAT_SLOW = -100;
|
|
public static final int FLASHBANG_MAX_DURATION = 60;
|
|
public static final int TRAP_HX2_MIN_BASE_DAMAGE = 4000;
|
|
public static final int TRAP_HX2_MAX_BASE_DAMAGE = 5500;
|
|
public static final float BASE_DETECT_CAMOUFLAGE_DISTANCE = 20;
|
|
public static final int PLAYER_DETECT_SAFETY_INTERVAL = 60;
|
|
public static final int MAX_INVIS_BUFF_TO_DETECT = 5;
|
|
public static final float BASE_DISARM_CHANCE = 55f;
|
|
public static final float MAX_CHANCE_TO_DISARM = 95f;
|
|
public static final float MIN_CHANCE_TO_DISARM = 10f;
|
|
public static final float PERCENT_EFFECT_MOD_DISARM_FAIL = 2f;
|
|
public static final float CHAFF_FLARE_DISTANCE = 15f;
|
|
public static final float MAX_BIO_PROBE_STORAGE_TIME = 3600;
|
|
public static final float MAX_PROBE_DISTANCE = 10f;
|
|
public static final String[] TRAP_RESTRICTED_REGIONS =
|
|
{
|
|
"dathomir_fs_village_unpassable"
|
|
};
|
|
public static void setBioProbeData(obj_id trap, obj_id target, String targetName) throws InterruptedException
|
|
{
|
|
}
|
|
public static void setTriggerData(obj_id trap, int triggerType, int accuracy, int param) throws InterruptedException
|
|
{
|
|
setObjVar(trap, TRAP_TR_ACCURACY, accuracy);
|
|
setObjVar(trap, TRIGGER_TYPE, triggerType);
|
|
switch (triggerType)
|
|
{
|
|
case TRIGGER_TYPE_TIMER:
|
|
setObjVar(trap, TIMER_TIME, param);
|
|
break;
|
|
case TRIGGER_TYPE_REMOTE:
|
|
String frequency = "" + rand(0, 999) + "." + rand(0, 999) + "." + rand(0, 999);
|
|
setObjVar(trap, stealth.TRAP_FREQUENCY, frequency);
|
|
break;
|
|
case TRIGGER_TYPE_PROXIMITY:
|
|
setObjVar(trap, PROXIMITY_RANGE, param);
|
|
break;
|
|
}
|
|
}
|
|
public static void createRangerLoot(int level, String object, obj_id container, int count) throws InterruptedException
|
|
{
|
|
object = toLower(object);
|
|
int type = 1;
|
|
int trigType = 1;
|
|
int power = getPowerLevel(level, false);
|
|
if (count < 0)
|
|
{
|
|
count = getNumLootItems(level, container);
|
|
}
|
|
int trigHash = getStringCrc(object.substring(0, 3));
|
|
int trapHash = getStringCrc(object.substring(4));
|
|
switch (trigHash)
|
|
{
|
|
case (265639046):
|
|
trigType = TRIGGER_TYPE_PROXIMITY;
|
|
break;
|
|
case (-1964272009):
|
|
trigType = TRIGGER_TYPE_TIMER;
|
|
break;
|
|
case (-1799474985):
|
|
trigType = TRIGGER_TYPE_REMOTE;
|
|
break;
|
|
default:
|
|
trapHash = getStringCrc(object);
|
|
break;
|
|
}
|
|
switch (trapHash)
|
|
{
|
|
case (-2001914999):
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
type = ALL_TRAP_TYPES[rand(0, ALL_TRAP_TYPES.length - 1)];
|
|
trigType = ALL_TRIGGER_TYPES[rand(0, ALL_TRIGGER_TYPES.length - 1)];
|
|
createTrapObject(container, getPowerLevel(level, true), type, 1, trigType, getPowerLevel(level, true), rand(5, 20));
|
|
}
|
|
break;
|
|
case (-279247418):
|
|
createMotionSensorObject(container, power, count);
|
|
break;
|
|
case (-1752438899):
|
|
createChaffFlareObject(container, power, count);
|
|
break;
|
|
case (487387167):
|
|
createHEPObject(container, power, count);
|
|
break;
|
|
case (1253827732):
|
|
createBioProbeObject(container, power, count);
|
|
break;
|
|
case (579649147):
|
|
createTrackingBeaconObject(container, power, count);
|
|
break;
|
|
case (240293015):
|
|
createTrapObject(container, power, TRAP_CALTROP, count, trigType, power, 10);
|
|
break;
|
|
case (1254944108):
|
|
createTrapObject(container, power, TRAP_FLASHBANG, count, trigType, power, 10);
|
|
break;
|
|
case (546611802):
|
|
createTrapObject(container, power, TRAP_HX2, count, trigType, power, 10);
|
|
break;
|
|
case (-1152836626):
|
|
createTrapObject(container, power, TRAP_KAMINODART, count, trigType, power, 10);
|
|
break;
|
|
}
|
|
}
|
|
public static void createRangerLoot(obj_id mob, int level, String object, obj_id container) throws InterruptedException
|
|
{
|
|
createRangerLoot(level, object, container, -1);
|
|
}
|
|
public static int getNumLootItems(int level, obj_id destContainer) throws InterruptedException
|
|
{
|
|
int numItems = 1 + (int)Math.ceil((level / 30));
|
|
int free = getVolumeFree(destContainer);
|
|
if (free < numItems)
|
|
{
|
|
numItems = free;
|
|
}
|
|
return numItems;
|
|
}
|
|
public static int getPowerLevel(int level, boolean includeVariance) throws InterruptedException
|
|
{
|
|
if (includeVariance)
|
|
{
|
|
return loot.getCalculatedAttribute(500, 1100, level, loot.MIN_CREATURE_LEVEL, loot.MAX_CREATURE_LEVEL);
|
|
}
|
|
float minPower = 500;
|
|
float maxPower = 1000;
|
|
float difference = maxPower - minPower;
|
|
float ratio = level / 100f;
|
|
return (int)Math.ceil(minPower + (difference * ratio));
|
|
}
|
|
public static obj_id createHEPObject(obj_id container, int power, int count) throws InterruptedException
|
|
{
|
|
String template = "object/tangible/scout/misc/hep.iff";
|
|
obj_id hep = null;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
hep = createObject(template, container, "");
|
|
if (!isIdValid(hep))
|
|
{
|
|
return null;
|
|
}
|
|
if (rand(0, 1) == 0)
|
|
{
|
|
setObjVar(hep, HEP_BASE_POWER, power);
|
|
setCount(hep, power);
|
|
setObjVar(hep, HEP_EFFECTIVENESS, Math.round((power / 2)));
|
|
}
|
|
else
|
|
{
|
|
setObjVar(hep, HEP_EFFECTIVENESS, power);
|
|
power = Math.round((power / 2));
|
|
setObjVar(hep, HEP_BASE_POWER, power);
|
|
setCount(hep, power);
|
|
}
|
|
}
|
|
return hep;
|
|
}
|
|
public static obj_id createTrackingBeaconObject(obj_id container, float power, int count) throws InterruptedException
|
|
{
|
|
String template = "object/tangible/scout/misc/trackingbeacon.iff";
|
|
obj_id probe = null;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
probe = createObject(template, container, "");
|
|
if (!isIdValid(probe))
|
|
{
|
|
return null;
|
|
}
|
|
setObjVar(probe, BEACON_BATTERY, power * 3);
|
|
setObjVar(probe, DETECT_EFFECTIVENESS, power);
|
|
setObjVar(probe, BIO_PROBE_STORAGE_TIME, MAX_BIO_PROBE_STORAGE_TIME);
|
|
}
|
|
return probe;
|
|
}
|
|
public static obj_id createBioProbeObject(obj_id container, float power, int count) throws InterruptedException
|
|
{
|
|
String template = "object/tangible/scout/misc/biosensorprobe.iff";
|
|
obj_id probe = null;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
probe = createObject(template, container, "");
|
|
if (!isIdValid(probe))
|
|
{
|
|
return null;
|
|
}
|
|
setObjVar(probe, BIO_PROBE_STORAGE_TIME, power / 1000 * MAX_BIO_PROBE_STORAGE_TIME);
|
|
}
|
|
return probe;
|
|
}
|
|
public static obj_id createMotionSensorObject(obj_id container, float batteryPower, int count) throws InterruptedException
|
|
{
|
|
String template = "object/tangible/scout/misc/motionsensor.iff";
|
|
obj_id sensor = null;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
sensor = createObject(template, container, "");
|
|
if (!isIdValid(sensor))
|
|
{
|
|
return null;
|
|
}
|
|
setObjVar(sensor, BEACON_BATTERY, batteryPower);
|
|
}
|
|
return sensor;
|
|
}
|
|
public static obj_id createChaffFlareObject(obj_id container, int power, int count) throws InterruptedException
|
|
{
|
|
String template = "object/tangible/scout/misc/chaffflare.iff";
|
|
obj_id flare = null;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
flare = createObject(template, container, "");
|
|
if (!isIdValid(flare))
|
|
{
|
|
return null;
|
|
}
|
|
setObjVar(flare, DETECT_EFFECTIVENESS, power);
|
|
}
|
|
return flare;
|
|
}
|
|
public static obj_id createTrapObject(obj_id container, int power, int trapType, int count, int triggerType, int triggerAccuracy, int triggerParam) throws InterruptedException
|
|
{
|
|
String template;
|
|
switch (trapType)
|
|
{
|
|
case TRAP_CALTROP:
|
|
template = "object/tangible/scout/trap/trap_ap_caltrop.iff";
|
|
break;
|
|
case TRAP_FLASHBANG:
|
|
template = "object/tangible/scout/trap/trap_ap_flashbang.iff";
|
|
break;
|
|
case TRAP_HX2:
|
|
template = "object/tangible/scout/trap/trap_ap_hx2mine.iff";
|
|
break;
|
|
case TRAP_KAMINODART:
|
|
template = "object/tangible/scout/trap/trap_ap_kaminoandart.iff";
|
|
break;
|
|
default:
|
|
template = "object/tangible/scout/trap/trap_ap_hx2mine.iff";
|
|
break;
|
|
}
|
|
obj_id trap = createObject(template, container, "");
|
|
if (!isIdValid(trap))
|
|
{
|
|
return null;
|
|
}
|
|
setObjVar(trap, TRAP_POWER, power);
|
|
setTriggerData(trap, triggerType, triggerAccuracy, triggerParam);
|
|
setCount(trap, count);
|
|
return trap;
|
|
}
|
|
public static boolean canPlaceMotionSensor(obj_id player, obj_id sensor) throws InterruptedException
|
|
{
|
|
obj_id[] stuff = getNonCreaturesInRange(getLocation(player), TRAP_MIN_DISTANCE_BETWEEN * 2);
|
|
for (obj_id aStuff : stuff) {
|
|
if (hasObjVar(aStuff, TRAP_TYPE) || hasObjVar(aStuff, BEACON_BATTERY)) {
|
|
sendSystemMessage(player, new string_id("spam", "other_trap"));
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
public static void placeMotionSensor(obj_id player, obj_id sensor) throws InterruptedException
|
|
{
|
|
location loc = getLocation(player);
|
|
if (!setLocation(sensor, loc))
|
|
{
|
|
return;
|
|
}
|
|
setObjVar(sensor, "armed", 1);
|
|
messageTo(sensor, "msgBatteryDead", null, getFloatObjVar(sensor, BEACON_BATTERY), true);
|
|
setObjVar(sensor, SENSOR_ARMED_TIME, getGameTime());
|
|
doAnimationAction(player, "point_down");
|
|
setOwner(sensor, player);
|
|
playClientEffectLoc(sensor, "clienteffect/frs_light_vigilance.cef", getLocation(sensor), 0.0f);
|
|
messageTo(sensor, "msgDeploy", null, 1, false);
|
|
}
|
|
public static void tripMotionSensor(obj_id sensor, obj_id breacher, boolean wasFiltered) throws InterruptedException
|
|
{
|
|
obj_id owner = getOwner(sensor);
|
|
if (!isIdValid(owner))
|
|
{
|
|
return;
|
|
}
|
|
if (hasObjVar(sensor, "lastSent"))
|
|
{
|
|
int lastTime = getIntObjVar(sensor, "lastSent");
|
|
if (lastTime + 30 > getGameTime())
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
setObjVar(sensor, "lastSent", getGameTime());
|
|
dictionary dic = new dictionary();
|
|
dic.put("sensor", sensor);
|
|
dic.put("breacherId", breacher);
|
|
dic.put("breacherName", isPlayer(breacher) ? getName(breacher) : getCreatureName(breacher));
|
|
dic.put("wasFiltered", wasFiltered);
|
|
dic.put("sensorLoc", getLocation(sensor));
|
|
messageTo(owner, "msgMotionSensorTripped", dic, 1, false);
|
|
}
|
|
public static void cleanComponentFromContainer(obj_id component, obj_id container) throws InterruptedException
|
|
{
|
|
if (!isIdValid(container))
|
|
{
|
|
return;
|
|
}
|
|
if (!hasObjVar(container, DETECT_EFFECTIVENESS) && !hasObjVar(container, TRAP_TYPE) && !hasObjVar(container, BEACON_BATTERY))
|
|
{
|
|
return;
|
|
}
|
|
obj_var_list ovl = getObjVarList(component, "trap");
|
|
if (ovl == null)
|
|
{
|
|
return;
|
|
}
|
|
int numItems = ovl.getNumItems();
|
|
obj_var ov;
|
|
for (int i = 0; i < numItems; i++)
|
|
{
|
|
ov = ovl.getObjVar(i);
|
|
if (ov != null)
|
|
{
|
|
removeObjVar(container, "trap." + ov.getName());
|
|
}
|
|
}
|
|
}
|
|
public static boolean canActivateTrackingBeacon(obj_id player, obj_id beacon, boolean silent) throws InterruptedException
|
|
{
|
|
if (!utils.testItemClassRequirements(player, beacon, false, "") || !utils.testItemLevelRequirements(player, beacon, false, ""))
|
|
{
|
|
return false;
|
|
}
|
|
obj_id target = getBioProbeTarget(beacon);
|
|
if (!isIdValid(target))
|
|
{
|
|
if (!silent)
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "bio_sample_bad"));
|
|
return false;
|
|
}
|
|
}
|
|
if (getFloatObjVar(beacon, BEACON_BATTERY) < BEACON_INTERVAL)
|
|
{
|
|
if (!silent)
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "traker_power_low"));
|
|
return false;
|
|
}
|
|
}
|
|
if (hasObjVar(beacon, BEACON_TARGET))
|
|
{
|
|
if (getObjIdObjVar(beacon, BEACON_TARGET) != target)
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "different_sample"));
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
public static void startTrackingBeacon(obj_id player, obj_id beacon) throws InterruptedException
|
|
{
|
|
obj_id target = getObjIdObjVar(beacon, BIO_PROBE_TRAP_TARGET);
|
|
if (!isIdValid(target))
|
|
{
|
|
return;
|
|
}
|
|
dictionary dic = new dictionary();
|
|
dic.put("sendingPlayer", player);
|
|
dic.put("sendingBeacon", beacon);
|
|
sendSystemMessage(player, new string_id("spam", "uploading_tracking"));
|
|
removeObjVar(beacon, BEACON_SHUTDOWN_PENDING);
|
|
if (!hasObjVar(beacon, BEACON_MSG_DISPATCHED))
|
|
{
|
|
setObjVar(beacon, BEACON_MSG_DISPATCHED, 1);
|
|
messageTo(beacon, "msgTrackingBeaconUpdate", dic, BEACON_INTERVAL, true);
|
|
messageTo(target, "msgTrackingBeaconLocationRequest", dic, 0, false);
|
|
}
|
|
}
|
|
public static void stopTrackingBeacon(obj_id beacon, obj_id player) throws InterruptedException
|
|
{
|
|
if (hasObjVar(beacon, BEACON_MSG_DISPATCHED))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "requestin_disconnect"));
|
|
setObjVar(beacon, BEACON_SHUTDOWN_PENDING, 1);
|
|
}
|
|
else if (isIdValid(player))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "connection_severed"));
|
|
removeObjVar(beacon, BEACON_LOCATION);
|
|
removeObjVar(beacon, BEACON_TARGET);
|
|
removeObjVar(beacon, BEACON_TARGET_NAME);
|
|
}
|
|
}
|
|
public static void updateTrackingBeaconDisplay(obj_id beacon) throws InterruptedException
|
|
{
|
|
obj_id player = utils.getContainingPlayer(beacon);
|
|
removeObjVar(beacon, BEACON_MSG_DISPATCHED);
|
|
if (hasObjVar(beacon, BEACON_SHUTDOWN_PENDING))
|
|
{
|
|
stopTrackingBeacon(beacon, player);
|
|
return;
|
|
}
|
|
float power = getFloatObjVar(beacon, BEACON_BATTERY);
|
|
power -= BEACON_INTERVAL;
|
|
setObjVar(beacon, BEACON_BATTERY, power);
|
|
if (!isIdValid(player))
|
|
{
|
|
stopTrackingBeacon(beacon, player);
|
|
return;
|
|
}
|
|
obj_id target = getObjIdObjVar(beacon, BEACON_TARGET);
|
|
if (!isIdValid(target))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "tracking_failed"));
|
|
}
|
|
else
|
|
{
|
|
setObjVar(beacon, BEACON_LAST_KNOWN_LOC, getLocationObjVar(beacon, BEACON_LOCATION));
|
|
setObjVar(beacon, BEACON_LAST_KNOWN_TARGET_NAME, getStringObjVar(beacon, BEACON_TARGET_NAME));
|
|
setObjVar(beacon, BEACON_LAST_KNOWN_TARGET, target);
|
|
prose_package pp = prose.getPackage(new string_id("spam", "tracker_updated"));
|
|
pp = prose.setTT(pp, target);
|
|
sendSystemMessageProse(player, pp);
|
|
}
|
|
if (canActivateTrackingBeacon(player, beacon, false))
|
|
{
|
|
if (!hasObjVar(beacon, BEACON_MSG_DISPATCHED))
|
|
{
|
|
dictionary dic = new dictionary();
|
|
dic.put("sendingPlayer", player);
|
|
dic.put("sendingBeacon", beacon);
|
|
sendSystemMessage(player, new string_id("spam", "requesting_target"));
|
|
setObjVar(beacon, BEACON_MSG_DISPATCHED, 1);
|
|
messageTo(beacon, "msgTrackingBeaconUpdate", dic, BEACON_INTERVAL, true);
|
|
messageTo(getObjIdObjVar(beacon, BEACON_TARGET), "msgTrackingBeaconLocationRequest", dic, 0, false);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
stopTrackingBeacon(beacon, player);
|
|
}
|
|
}
|
|
public static void updateTrackingBeaconData(obj_id beacon, obj_id target, location targetLoc, String targetName) throws InterruptedException
|
|
{
|
|
setObjVar(beacon, BEACON_LOCATION, targetLoc);
|
|
setObjVar(beacon, BEACON_TARGET, target);
|
|
setObjVar(beacon, BEACON_TARGET_NAME, targetName);
|
|
}
|
|
public static obj_id getBioProbeTarget(obj_id thing) throws InterruptedException
|
|
{
|
|
obj_id target = null;
|
|
if ((hasObjVar(thing, TRAP_TYPE) || hasObjVar(thing, BEACON_BATTERY)) && hasObjVar(thing, BIO_PROBE_TRAP_TARGET))
|
|
{
|
|
if (hasObjVar(thing, BIO_PROBE_STORAGE_TIME))
|
|
{
|
|
if (!hasObjVar(thing, BIO_PROBE_DECAYED))
|
|
{
|
|
target = getObjIdObjVar(thing, BIO_PROBE_TRAP_TARGET);
|
|
}
|
|
}
|
|
}
|
|
return target;
|
|
}
|
|
public static boolean canBioProbe(obj_id player, obj_id probe, obj_id target) throws InterruptedException
|
|
{
|
|
if (!isIdValid(target))
|
|
{
|
|
showFlyTextPrivate(player, player, new string_id("spam", "bad_target"), 1.5f, colors.TOMATO);
|
|
return false;
|
|
}
|
|
if (!ai_lib.isHumanoid(target))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "sample_humanoid"));
|
|
return false;
|
|
}
|
|
if (!pvpCanAttack(player, target))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_sample"));
|
|
return false;
|
|
}
|
|
if (getDistance(getLocation(player), getLocation(target)) > MAX_PROBE_DISTANCE)
|
|
{
|
|
showFlyTextPrivate(player, player, new string_id("spam", "too_far"), 1.5f, colors.TOMATO);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
public static void bioProbe(obj_id player, obj_id probe, obj_id target) throws InterruptedException
|
|
{
|
|
float timeToDecay = getFloatObjVar(probe, BIO_PROBE_STORAGE_TIME);
|
|
setObjVar(probe, BIO_PROBE_SAMPLE_TIME, getGameTime());
|
|
messageTo(probe, "msgDecaySample", null, timeToDecay, true);
|
|
doAnimationAction(player, "heal_other");
|
|
setObjVar(probe, BIO_PROBE_TRAP_TARGET, target);
|
|
setObjVar(probe, BIO_PROBE_TARGET_NAME, isPlayer(target) ? getName(target) : "a " + getCreatureName(target));
|
|
if (isPlayer(target))
|
|
{
|
|
prose_package pp = prose.getPackage(new string_id("spam", "feel_twinge"));
|
|
pp = prose.setTT(pp, player);
|
|
sendSystemMessageProse(target, pp);
|
|
}
|
|
prose_package pp = prose.getPackage(new string_id("spam", "got_probe"));
|
|
pp = prose.setTT(pp, target);
|
|
sendSystemMessageProse(player, pp);
|
|
}
|
|
public static void doChaffFlareEffect(obj_id player, obj_id flare) throws InterruptedException
|
|
{
|
|
doAnimationAction(player, "manipulate_high");
|
|
playClientEffectLoc(player, "appearance/pt_sparking_blast_md.prt", getLocation(player), 0.0f);
|
|
float flareDistance = CHAFF_FLARE_DISTANCE;
|
|
float detectSkill = getEnhancedSkillStatisticModifier(player, "detect_hidden");
|
|
obj_id[] stuff = getObjectsInRange(player, flareDistance);
|
|
boolean foundSomething = false;
|
|
prose_package pp = prose.getPackage(new string_id("spam", "chaff_uncover"));
|
|
pp = prose.setTT(pp, player);
|
|
for (obj_id aStuff : stuff) {
|
|
if (!hasObjVar(aStuff, TRAP_TYPE) || !validateTrapTarget(aStuff, player)) {
|
|
continue;
|
|
}
|
|
int hidePower = getIntObjVar(aStuff, CAMO_SKILL);
|
|
int chaffPower = getIntObjVar(flare, DETECT_EFFECTIVENESS);
|
|
if (hidePower > chaffPower) {
|
|
continue;
|
|
}
|
|
pp = prose.setTU(pp, aStuff);
|
|
foundSomething = true;
|
|
unconcealDevice(player, aStuff);
|
|
}
|
|
if (foundSomething)
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "chaff_foundsomething"));
|
|
doAnimationAction(player, "point_forward");
|
|
}
|
|
else
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "chaff_nothing"));
|
|
}
|
|
}
|
|
public static boolean canDisarmTrap(obj_id player, obj_id trap) throws InterruptedException
|
|
{
|
|
if (!hasObjVar(trap, TRAP_TYPE) && !hasObjVar(trap, BEACON_BATTERY))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "bad_disarm_target"));
|
|
return false;
|
|
}
|
|
if (!validateTrapTarget(trap, player) && getOwner(trap) != player)
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_disarm"));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
public static void disarmTrap(obj_id player, obj_id trap) throws InterruptedException
|
|
{
|
|
if (getOwner(trap) == player || hasObjVar(trap, BEACON_BATTERY))
|
|
{
|
|
showFlyText(trap, new string_id("spam", "disarm_go"), 1.5f, colors.TOMATO);
|
|
sendSystemMessage(player, new string_id("spam", "disarm"));
|
|
playTrapFizzle(trap);
|
|
destroyObject(trap);
|
|
return;
|
|
}
|
|
float baseChanceToDisarm = BASE_DISARM_CHANCE;
|
|
int trapLevel = getIntObjVar(trap, TRAP_LEVEL);
|
|
int trapSkillMod = getIntObjVar(trap, TRAP_DIFFICULTY);
|
|
float trapperScore = trapLevel + trapSkillMod;
|
|
int diffuserLevel = getLevel(player);
|
|
int diffuserSkillMod = getEnhancedSkillStatisticModifier(player, "ranger_trap");
|
|
int spyBonus = utils.isProfession(player, utils.SPY) ? 30 : 0;
|
|
float diffuserScore = diffuserLevel + diffuserSkillMod + spyBonus;
|
|
float totalDisparity = diffuserScore - trapperScore;
|
|
float chanceToDetect = baseChanceToDisarm;
|
|
float detectRange = MAX_CHANCE_TO_DISARM - MIN_CHANCE_TO_DISARM;
|
|
if (totalDisparity > 0)
|
|
{
|
|
chanceToDetect += (totalDisparity / MAX_HIDING_DETECT_SCORE) * detectRange;
|
|
}
|
|
if (chanceToDetect > MAX_CHANCE_TO_DISARM)
|
|
{
|
|
chanceToDetect = MAX_CHANCE_TO_DISARM;
|
|
}
|
|
if (rand(0f, 100f) < chanceToDetect)
|
|
{
|
|
if (hasObjVar(trap, stealth.TRAP_FREQUENCY))
|
|
{
|
|
obj_id myRemote = getObjIdObjVar(trap, stealth.TRAP_MY_PROXIMITY_TRIGGER);
|
|
if (exists(myRemote))
|
|
{
|
|
messageTo(myRemote, "trapDisarmed", null, 1, false);
|
|
}
|
|
}
|
|
showFlyText(trap, new string_id("spam", "disarm_go"), 1.5f, colors.TOMATO);
|
|
sendSystemMessage(player, new string_id("spam", "disarm"));
|
|
playTrapFizzle(trap);
|
|
destroyObject(trap);
|
|
}
|
|
else
|
|
{
|
|
if (hasObjVar(trap, stealth.TRAP_FREQUENCY))
|
|
{
|
|
obj_id myRemote = getObjIdObjVar(trap, stealth.TRAP_MY_PROXIMITY_TRIGGER);
|
|
if (exists(myRemote))
|
|
{
|
|
messageTo(myRemote, "trapDisarmed", null, 1, false);
|
|
}
|
|
}
|
|
Vector target = new Vector();
|
|
target.add(player);
|
|
doTrapDetonateEffect(trap, getIntObjVar(trap, TRAP_TYPE), target, PERCENT_EFFECT_MOD_DISARM_FAIL);
|
|
sendSystemMessage(player, new string_id("spam", "fail_disarm"));
|
|
}
|
|
}
|
|
public static boolean canDetectCamouflage(obj_id player) throws InterruptedException
|
|
{
|
|
return true;
|
|
}
|
|
public static void detectCamouflage(obj_id player, boolean findMobiles, boolean findInanimate, float distance, float baseChanceToDetect) throws InterruptedException
|
|
{
|
|
obj_id[] stuff = getObjectsInRange(player, distance);
|
|
Vector detected;
|
|
Vector times;
|
|
int now = getGameTime();
|
|
boolean foundSomething = false;
|
|
obj_id target;
|
|
String invis;
|
|
boolean objIsMobile;
|
|
location playerLoc = getLocation(player);
|
|
playClientEffectLoc(getPlayerCreaturesInRange(playerLoc, 100.0f), "appearance/pt_spy_reveal_wave.prt", playerLoc, 0.0f);
|
|
if (utils.isProfession(player, utils.SPY))
|
|
{
|
|
invis = getInvisBuff(player);
|
|
if (invis == null)
|
|
{
|
|
playClientEffectLoc(player, "appearance/pt_spy_expose_shadows.prt", getLocation(player), 0.0f);
|
|
}
|
|
else
|
|
{
|
|
Vector clients = new Vector();
|
|
clients = utils.addElement(clients, player);
|
|
dictionary revealList = getPassiveRevealList(player);
|
|
if (revealList != null)
|
|
{
|
|
Vector ids = revealList.getResizeableObjIdArray("id");
|
|
if ((ids != null) && (ids.size() != 0))
|
|
{
|
|
clients = utils.concatArrays(clients, ids);
|
|
}
|
|
}
|
|
playClientEffectLoc(utils.toStaticObjIdArray(clients), "appearance/pt_spy_expose_shadows.prt", getLocation(player), 0.0f);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
playClientEffectLoc(player, "appearance/pt_fireworks_secondary_shockwave2.prt", getLocation(player), 0.0f);
|
|
}
|
|
for (obj_id aStuff : stuff) {
|
|
objIsMobile = false;
|
|
target = aStuff;
|
|
if (!isIdValid(target)) {
|
|
continue;
|
|
}
|
|
if (isPlayer(target) || ai_lib.isHumanoid(target) || isMob(target)) {
|
|
objIsMobile = true;
|
|
if (!pvpCanAttack(player, target)) {
|
|
continue;
|
|
}
|
|
invis = getInvisBuff(target);
|
|
if (invis == null) {
|
|
continue;
|
|
} else if (buff.getPriority(invis) > MAX_INVIS_BUFF_TO_DETECT) {
|
|
continue;
|
|
}
|
|
if (invis.startsWith("invis_sp_buff_invis_notrace") || invis.startsWith("invis_sp_diversion_stealth")) {
|
|
continue;
|
|
}
|
|
detected = utils.getResizeableStringBatchObjVar(target, DETECT_ATTEMPTS);
|
|
times = utils.getResizeableStringBatchObjVar(target, DETECT_TIMES);
|
|
if (detected == null) {
|
|
detected = new Vector();
|
|
}
|
|
if (times == null) {
|
|
times = new Vector();
|
|
}
|
|
if (detected.size() != times.size()) {
|
|
continue;
|
|
}
|
|
int idx = detected.indexOf(player);
|
|
if (idx > -1) {
|
|
int when = (Integer) times.get(idx);
|
|
if (when - now < PLAYER_DETECT_SAFETY_INTERVAL) {
|
|
continue;
|
|
}
|
|
times.setElementAt(now, idx);
|
|
} else {
|
|
detected.add(player);
|
|
times.add(now);
|
|
}
|
|
utils.setResizeableBatchObjVar(target, DETECT_ATTEMPTS, detected);
|
|
utils.setResizeableBatchObjVar(target, DETECT_TIMES, times);
|
|
} else if (!hasObjVar(target, CONCEALED_OBJECT) || !validateTrapTarget(target, player)) {
|
|
continue;
|
|
}
|
|
if (activeDetectHiddenTarget(target, player, baseChanceToDetect)) {
|
|
if (objIsMobile) {
|
|
checkForAndMakeVisible(target);
|
|
} else {
|
|
unconcealDevice(player, target);
|
|
}
|
|
foundSomething = true;
|
|
playClientEffectLoc(target, "clienteffect/lair_med_damage_smoke.cef", getLocation(target), 0.0f);
|
|
}
|
|
}
|
|
if (foundSomething)
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "detected_something"));
|
|
doAnimationAction(player, "point_forward");
|
|
}
|
|
else
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "no_detect"));
|
|
}
|
|
}
|
|
public static boolean canConcealDevice(obj_id player, obj_id target) throws InterruptedException
|
|
{
|
|
if (!isIdValid(target) || !exists(target))
|
|
{
|
|
return false;
|
|
}
|
|
if (!hasObjVar(target, CONCEALABLE_DEVICE))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_conceal_that"));
|
|
return false;
|
|
}
|
|
if (hasObjVar(target, CONCEALED_OBJECT))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "already_concealed"));
|
|
return false;
|
|
}
|
|
obj_id owner = getOwner(target);
|
|
if (owner != player)
|
|
{
|
|
if (!group.inSameGroup(player, owner))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_conceal_owner"));
|
|
return false;
|
|
}
|
|
}
|
|
if (getDistance(getLocation(target), getLocation(player)) > 15)
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "too_far_conceal"));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
public static void concealDevice(obj_id player, obj_id target) throws InterruptedException
|
|
{
|
|
int camoSkill = getEnhancedSkillStatisticModifier(player, "camouflage");
|
|
camoSkill += getEnhancedSkillStatisticModifier(player, "stealth");
|
|
setObjVar(target, CONCEALED_OBJECT, 1);
|
|
setObjVar(target, CAMO_SKILL, camoSkill);
|
|
setObjVar(target, CAMOUFLAGED_AT_LEVEL, getLevel(player));
|
|
hideFromClient(target, true);
|
|
}
|
|
public static void unconcealDevice(obj_id player, obj_id target) throws InterruptedException
|
|
{
|
|
removeObjVar(target, CONCEALED_OBJECT);
|
|
removeObjVar(target, CAMO_SKILL);
|
|
removeObjVar(target, CAMOUFLAGED_AT_LEVEL);
|
|
hideFromClient(target, false);
|
|
location loc = getLocation(target);
|
|
loc.y -= 10;
|
|
playClientEffectLoc(player, "clienteffect/frs_dark_vengeance.cef", loc, 0);
|
|
stopClientEffectObjByLabel(target, "trapConceal");
|
|
doAnimationAction(player, "point_down");
|
|
}
|
|
public static boolean canSetTrap(obj_id player, obj_id trap) throws InterruptedException
|
|
{
|
|
if (!isIdValid(trap) || !hasScript(trap, "systems.skills.stealth.trap"))
|
|
{
|
|
return false;
|
|
}
|
|
if (ai_lib.isInCombat(player))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "trap_not_in_combat"));
|
|
return false;
|
|
}
|
|
if (!utils.isNestedWithin(trap, player))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "trap_not_possession"));
|
|
return false;
|
|
}
|
|
if (isPvPTrap(trap) && !factions.isDeclared(player))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "trap_not_declared"));
|
|
return false;
|
|
}
|
|
if (pet_lib.isMounted(player))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "trap_not_while_mounted"));
|
|
return false;
|
|
}
|
|
if (!hasObjVar(trap, TRIGGER_TYPE))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "trap_no_trigger_installed"));
|
|
return false;
|
|
}
|
|
if (locations.isInCity(getLocation(player)))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "no_trap_city"));
|
|
return false;
|
|
}
|
|
if (inTrapRestrictedRegion(player))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "trap_restricted_region"));
|
|
return false;
|
|
}
|
|
if (utils.isInHouseCellSpace(player))
|
|
{
|
|
obj_id house = getTopMostContainer(player);
|
|
if (hasObjVar(house, "player_structure.admin.adminList"))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "trap_not_house"));
|
|
return false;
|
|
}
|
|
}
|
|
obj_id[] stuff = getNonCreaturesInRange(getLocation(player), TRAP_MIN_DISTANCE_BETWEEN);
|
|
for (obj_id aStuff : stuff) {
|
|
if (hasObjVar(aStuff, TRAP_TYPE)) {
|
|
sendSystemMessage(player, new string_id("spam", "other_trap"));
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
public static boolean inTrapRestrictedRegion(obj_id player) throws InterruptedException
|
|
{
|
|
for (String TRAP_RESTRICTED_REGION : TRAP_RESTRICTED_REGIONS) {
|
|
if (groundquests.isInNamedRegion(player, TRAP_RESTRICTED_REGION)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
public static void onGetTrapAttributes(obj_id self, obj_id player, String[] names, String[] attribs, int free) throws InterruptedException
|
|
{
|
|
if (free == -1)
|
|
{
|
|
return;
|
|
}
|
|
if (hasObjVar(self, TRAP_TYPE))
|
|
{
|
|
switch (getIntObjVar(self, TRAP_TYPE)) {
|
|
case TRAP_CALTROP: {
|
|
float trapRadiusFlt = TRAP_CALTROP_BLAST_RADIUS;
|
|
names[free] = "trap_radius";
|
|
attribs[free++] = "" + trapRadiusFlt + "m";
|
|
break;
|
|
}
|
|
case TRAP_FLASHBANG: {
|
|
float trapRadiusFlt = TRAP_FLASHBANG_BLAST_RADIUS;
|
|
names[free] = "trap_radius";
|
|
attribs[free++] = "" + trapRadiusFlt + "m";
|
|
break;
|
|
}
|
|
case TRAP_HX2: {
|
|
float trapRadiusFlt = TRAP_HX2_BLAST_RADIUS;
|
|
names[free] = "trap_radius";
|
|
attribs[free++] = "" + trapRadiusFlt + "m";
|
|
break;
|
|
}
|
|
case TRAP_KAMINODART: {
|
|
float trapRadiusFlt = TRAP_KAMINODART_BLAST_RADIUS;
|
|
names[free] = "trap_radius";
|
|
attribs[free++] = "" + trapRadiusFlt + "m";
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (hasObjVar(self, TRAP_POWER))
|
|
{
|
|
names[free] = "trap_power";
|
|
attribs[free++] = "" + floatFormat.format(getIntObjVar(self, TRAP_POWER) / 10) + "%";
|
|
}
|
|
if (hasObjVar(self, TIMER_TIME) && (utils.isNestedWithin(self, player) || getOwner(self) == player))
|
|
{
|
|
names[free] = "trigger_time";
|
|
attribs[free++] = "" + getIntObjVar(self, TIMER_TIME) + " seconds";
|
|
names[free] = "tooltip.trap_type";
|
|
attribs[free++] = "@spam:trap_trigger_timed";
|
|
names[free] = "trap_type";
|
|
attribs[free++] = "@spam:trap_trig_desc_timed";
|
|
}
|
|
if (hasObjVar(self, PROXIMITY_RANGE) && (utils.isNestedWithin(self, player) || getOwner(self) == player))
|
|
{
|
|
names[free] = "trigger_proximity";
|
|
int proximityRange = getIntObjVar(self, PROXIMITY_RANGE);
|
|
String meterPluralization = " meters";
|
|
if (proximityRange == 1)
|
|
{
|
|
meterPluralization = " meter";
|
|
}
|
|
attribs[free++] = "" + proximityRange + meterPluralization;
|
|
names[free] = "tooltip.trap_type";
|
|
attribs[free++] = "@spam:trap_trigger_proximity";
|
|
names[free] = "trap_type";
|
|
attribs[free++] = "@spam:trap_trig_desc_proximity";
|
|
}
|
|
if (hasObjVar(self, TRAP_FREQUENCY) && (utils.isNestedWithin(self, player) || getOwner(self) == player))
|
|
{
|
|
names[free] = "tooltip.trap_type";
|
|
attribs[free++] = "@spam:trap_trigger_remote";
|
|
names[free] = "trap_type";
|
|
attribs[free++] = "@spam:trap_trig_desc_remote";
|
|
}
|
|
if (hasObjVar(self, TRAP_FREQUENCY) && hasObjVar(self, "armed"))
|
|
{
|
|
names[free] = "trap_frequency";
|
|
attribs[free++] = "" + getStringObjVar(self, TRAP_FREQUENCY) + " mHz";
|
|
}
|
|
if (hasObjVar(self, BIO_PROBE_TRAP_TARGET))
|
|
{
|
|
names[free] = "trigger_filter";
|
|
attribs[free++] = "" + getStringObjVar(self, BIO_PROBE_TARGET_NAME);
|
|
}
|
|
utils.addClassRequirementAttributes(player, self, names, attribs, free, "trap.");
|
|
utils.addClassRequirementAttributes(player, self, names, attribs, free, "trap.trigger.");
|
|
}
|
|
public static boolean tryDetonateTrap(obj_id trap, obj_id target) throws InterruptedException
|
|
{
|
|
if (!hasObjVar(trap, "armed"))
|
|
{
|
|
return false;
|
|
}
|
|
int trapType = getIntObjVar(trap, TRAP_TYPE);
|
|
int triggerAccuracy = getIntObjVar(trap, TRAP_TR_ACCURACY);
|
|
boolean success = rand(1, 100) <= triggerAccuracy;
|
|
if (!success)
|
|
{
|
|
playTrapFizzle(trap);
|
|
if (getIntObjVar(trap, TRIGGER_TYPE) == TRIGGER_TYPE_TIMER)
|
|
{
|
|
dictionary parms = new dictionary();
|
|
int time = getGameTime();
|
|
parms.put("armed", time);
|
|
float newTime = getIntObjVar(trap, TIMER_TIME) * rand(0.1f, 0.25f);
|
|
messageTo(trap, "msgTryDetonateTimer", parms, newTime, false);
|
|
setObjVar(trap, "armed", time);
|
|
}
|
|
return false;
|
|
}
|
|
Vector targets = getTrapTargets(trap, trapType);
|
|
if (validateTrapTarget(trap, target) && targets.indexOf(target) == -1)
|
|
{
|
|
targets.add(target);
|
|
}
|
|
hideFromClient(trap, false);
|
|
doTrapDetonateEffect(trap, trapType, targets, 0, target);
|
|
return true;
|
|
}
|
|
public static Vector getTrapTargets(obj_id trap, int trapType) throws InterruptedException
|
|
{
|
|
obj_id[] targets = new obj_id[0];
|
|
switch (trapType)
|
|
{
|
|
case TRAP_HX2:
|
|
targets = getCreaturesInRange(getLocation(trap), TRAP_HX2_BLAST_RADIUS);
|
|
break;
|
|
case TRAP_FLASHBANG:
|
|
targets = getCreaturesInRange(getLocation(trap), TRAP_FLASHBANG_BLAST_RADIUS);
|
|
break;
|
|
case TRAP_CALTROP:
|
|
targets = getCreaturesInRange(getLocation(trap), TRAP_CALTROP_BLAST_RADIUS);
|
|
break;
|
|
case TRAP_KAMINODART:
|
|
targets = getCreaturesInRange(getLocation(trap), TRAP_KAMINODART_BLAST_RADIUS);
|
|
break;
|
|
}
|
|
Vector finalTargets = new Vector();
|
|
obj_id filter = getBioProbeTarget(trap);
|
|
for (obj_id target : targets) {
|
|
if (!isIdValid(filter) || target == filter) {
|
|
if (validateTrapTarget(trap, target)) {
|
|
finalTargets.add(target);
|
|
}
|
|
}
|
|
}
|
|
return finalTargets;
|
|
}
|
|
public static void doTrapDetonateEffect(obj_id trap, int trapType, Vector targets, float percentMod, obj_id breacher) throws InterruptedException
|
|
{
|
|
if (targets.size() > 0)
|
|
{
|
|
switch (trapType)
|
|
{
|
|
case TRAP_HX2:
|
|
dictionary params = new dictionary();
|
|
obj_id owner = getOwner(trap);
|
|
if (!isIdValid(breacher))
|
|
{
|
|
breacher = (obj_id)targets.elementAt(0);
|
|
if (!isIdValid(breacher))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
params.put("target", breacher);
|
|
params.put("owner", owner);
|
|
messageTo(trap, "co_mine_hx2", params, 0, false);
|
|
break;
|
|
case TRAP_FLASHBANG:
|
|
doFlashBangDetonate(trap, targets, percentMod);
|
|
break;
|
|
case TRAP_CALTROP:
|
|
doCaltropDetonate(trap, targets, percentMod);
|
|
break;
|
|
case TRAP_KAMINODART:
|
|
doKaminoDartDetonate(trap, targets, percentMod);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
playClientEffectLoc(trap, "clienteffect/lair_damage_heavy.cef", getLocation(trap), 0.0f);
|
|
}
|
|
destroyObject(trap);
|
|
}
|
|
public static void doTrapDetonateEffect(obj_id trap, int trapType, Vector targets) throws InterruptedException
|
|
{
|
|
doTrapDetonateEffect(trap, trapType, targets, 0);
|
|
}
|
|
public static void doTrapDetonateEffect(obj_id trap, int trapType, Vector targets, float percentMod) throws InterruptedException
|
|
{
|
|
doTrapDetonateEffect(trap, trapType, targets, 0, null);
|
|
}
|
|
public static void doKaminoDartDetonate(obj_id trap, Vector targets) throws InterruptedException
|
|
{
|
|
doKaminoDartDetonate(trap, targets, 0);
|
|
}
|
|
public static void doKaminoDartDetonate(obj_id trap, Vector targets, float percentMod) throws InterruptedException
|
|
{
|
|
float trapPower = getIntObjVar(trap, TRAP_POWER);
|
|
int potency = (int)(KAMINODART_MAX_POTENCY * (trapPower / 1000));
|
|
int duration = (int)(KAMINODART_MAX_DURATION * (trapPower / 1000));
|
|
int strength = (int)(KAMINODART_MAX_STRENGTH * (trapPower / 1000));
|
|
obj_id owner = getOwner(trap);
|
|
boolean isInvis;
|
|
String invis = null;
|
|
boolean attackerPresent = false;
|
|
if (isIdValid(owner) && exists(owner))
|
|
{
|
|
attackerPresent = true;
|
|
invis = getInvisBuff(getOwner(trap));
|
|
}
|
|
isInvis = invis != null && invis.length() > 0;
|
|
duration += duration * percentMod;
|
|
strength += strength * percentMod;
|
|
obj_id curObj;
|
|
prose_package pp = prose.getPackage(new string_id("spam", "kamino_trap_hit"));
|
|
//playClientEffectLoc(trap, "clienteffect/lair_damage_light.cef", getLocation(curObj), 0.0f);
|
|
for (Object target : targets) {
|
|
curObj = (obj_id) target;
|
|
playClientEffectLoc(curObj, "clienteffect/lair_damage_light.cef", getLocation(curObj), 0.0f);
|
|
dot.applyDotEffect(curObj, owner, dot.DOT_POISON, "rangerTrapKaminoDart", HEALTH, potency, strength, duration, true, null);
|
|
pp = prose.setTT(pp, curObj);
|
|
if (attackerPresent) {
|
|
if (isInvis && rand(1, 100) < 50) {
|
|
continue;
|
|
}
|
|
startCombat(curObj, owner);
|
|
}
|
|
}
|
|
}
|
|
public static void doCaltropDetonate(obj_id trap, Vector targets) throws InterruptedException
|
|
{
|
|
doCaltropDetonate(trap, targets, 0);
|
|
}
|
|
public static void doCaltropDetonate(obj_id trap, Vector targets, float percentMod) throws InterruptedException
|
|
{
|
|
float trapPower = getIntObjVar(trap, TRAP_POWER);
|
|
float duration = CALTROP_MAX_DURATION * (trapPower / 1000);
|
|
float snareAmount = CALTROP_MAX_SNARE * (trapPower / 1000);
|
|
obj_id curObj;
|
|
obj_id owner = getOwner(trap);
|
|
boolean isInvis;
|
|
String invis = null;
|
|
boolean attackerPresent = false;
|
|
if (isIdValid(owner) && exists(owner))
|
|
{
|
|
attackerPresent = true;
|
|
invis = getInvisBuff(getOwner(trap));
|
|
}
|
|
isInvis = invis != null && invis.length() > 0;
|
|
playClientEffectLoc(trap, "clienteffect/lair_med_damage_smoke.cef", getLocation(trap), 0.0f);
|
|
duration += duration * percentMod;
|
|
snareAmount += snareAmount * percentMod;
|
|
if (snareAmount > 95)
|
|
{
|
|
snareAmount = 95;
|
|
}
|
|
for (Object target : targets) {
|
|
curObj = (obj_id) target;
|
|
if (buff.canApplyBuff(curObj, "caltropSnare")) {
|
|
playClientEffectLoc(curObj, "clienteffect/lair_damage_light.cef", getLocation(curObj), 0.0f);
|
|
buff.applyBuff(curObj, "caltropSnare", duration, snareAmount);
|
|
if (attackerPresent) {
|
|
if (isInvis && rand(1, 100) < 50) {
|
|
continue;
|
|
}
|
|
startCombat(curObj, owner);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
public static void doFlashBangDetonate(obj_id trap, Vector targets) throws InterruptedException
|
|
{
|
|
doFlashBangDetonate(trap, targets, 0);
|
|
}
|
|
public static void doFlashBangDetonate(obj_id trap, Vector targets, float percentMod) throws InterruptedException
|
|
{
|
|
float trapPower = getIntObjVar(trap, TRAP_POWER);
|
|
float duration = FLASHBANG_MAX_DURATION * (trapPower / 1000);
|
|
float amount = FLASHBANG_MAX_COMBAT_SLOW * (trapPower / 1000);
|
|
obj_id curObj;
|
|
obj_id owner = getOwner(trap);
|
|
boolean isInvis;
|
|
String invis = null;
|
|
boolean attackerPresent = false;
|
|
if (isIdValid(owner) && exists(owner))
|
|
{
|
|
attackerPresent = true;
|
|
invis = getInvisBuff(getOwner(trap));
|
|
}
|
|
isInvis = invis != null && invis.length() > 0;
|
|
playClientEffectLoc(trap, "clienteffect/int_camshake_light.cef", getLocation(trap), 0.0f);
|
|
playClientEffectLoc(trap, "appearance/pt_flash_bomb.prt", getLocation(trap), 0.0f);
|
|
duration += duration * percentMod;
|
|
amount += amount * percentMod;
|
|
for (Object target : targets) {
|
|
curObj = (obj_id) target;
|
|
if (buff.canApplyBuff(curObj, "flashBang")) {
|
|
if (isPlayer(curObj)) {
|
|
doAnimationAction(curObj, "cover_ears_mocking");
|
|
}
|
|
buff.applyBuff(curObj, "flashBang", duration, amount);
|
|
if (attackerPresent) {
|
|
if (isInvis && rand(1, 100) < 50) {
|
|
continue;
|
|
}
|
|
startCombat(curObj, owner);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
public static boolean safePvPCanAttack(obj_id trap, obj_id target) throws InterruptedException
|
|
{
|
|
obj_id trapOwner = getOwner(trap);
|
|
if (isIdValid(trapOwner) && exists(trapOwner))
|
|
{
|
|
return pvpCanAttack(trapOwner, target);
|
|
}
|
|
if (isInvulnerable(target))
|
|
{
|
|
return false;
|
|
}
|
|
if (trapOwner == target)
|
|
{
|
|
return false;
|
|
}
|
|
boolean actorIsPlayer = true;
|
|
int actorFaction = getIntObjVar(trap, TRAP_FACTION);
|
|
int actorPvPType = getIntObjVar(trap, TRAP_PVP_TYPE);
|
|
int targetFaction = pvpGetAlignedFaction(target);
|
|
boolean targetIsPlayer = isPlayer(target);
|
|
int targetPvPType = pvpGetType(target);
|
|
if (targetIsPlayer && actorPvPType != PVPTYPE_DECLARED)
|
|
{
|
|
return false;
|
|
}
|
|
if (targetIsPlayer)
|
|
{
|
|
if (pvpAreFactionsOpposed(actorFaction, targetFaction))
|
|
{
|
|
if (targetPvPType == PVPTYPE_DECLARED)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
if (!targetIsPlayer)
|
|
{
|
|
if (targetFaction != 0) {
|
|
return actorFaction != targetFaction && pvpAreFactionsOpposed(actorFaction, targetFaction);
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
public static boolean validateTrapTarget(obj_id trap, obj_id target) throws InterruptedException
|
|
{
|
|
if (!isIdValid(target) || trap == target)
|
|
{
|
|
return false;
|
|
}
|
|
if (isDead(target))
|
|
{
|
|
return false;
|
|
}
|
|
if (isIncapacitated(target))
|
|
{
|
|
return false;
|
|
}
|
|
if (!safePvPCanAttack(trap, target))
|
|
{
|
|
return false;
|
|
}
|
|
location trapLoc = getLocation(trap);
|
|
trapLoc.y += 0.5f;
|
|
if (!canSee(target, trapLoc))
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
public static void playTrapFizzle(obj_id trap) throws InterruptedException
|
|
{
|
|
playClientEffectLoc(trap, "clienteffect/frs_light_serenity.cef", getLocation(trap), 0.0f);
|
|
}
|
|
public static void playSelfDestruct(obj_id trap) throws InterruptedException
|
|
{
|
|
playClientEffectLoc(trap, "clienteffect/combat_grenade_thermal_detonator.cef", getLocation(trap), 0.0f);
|
|
}
|
|
public static boolean setTrap(obj_id player, obj_id invTrap) throws InterruptedException
|
|
{
|
|
if (!hasObjVar(invTrap, TRIGGER_TYPE))
|
|
{
|
|
return false;
|
|
}
|
|
int count = getCount(invTrap);
|
|
if (count < 1)
|
|
{
|
|
destroyObject(invTrap);
|
|
return false;
|
|
}
|
|
location loc = getLocation(player);
|
|
int triggerType = getIntObjVar(invTrap, TRIGGER_TYPE);
|
|
obj_id trap = utils.cloneObject(invTrap, loc);
|
|
int time = getGameTime();
|
|
if (!isIdValid(trap))
|
|
{
|
|
return false;
|
|
}
|
|
switch (triggerType)
|
|
{
|
|
case TRIGGER_TYPE_TIMER:
|
|
dictionary parms = new dictionary();
|
|
parms.put("armed", time);
|
|
messageTo(trap, "msgTryDetonateTimer", parms, getIntObjVar(trap, TIMER_TIME), false);
|
|
setObjVar(trap, "armed", time);
|
|
break;
|
|
case TRIGGER_TYPE_REMOTE:
|
|
obj_id pInv = utils.getInventoryContainer(player);
|
|
int free = getVolumeFree(pInv);
|
|
if (free < 1)
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "no_room_remote_trigger"));
|
|
return false;
|
|
}
|
|
String remote = "object/tangible/scout/trap/trap_ap_tr_remote.iff";
|
|
obj_id remoteTrigger = createObject(remote, pInv, "");
|
|
if (!isIdValid(remoteTrigger))
|
|
{
|
|
destroyObject(trap);
|
|
return false;
|
|
}
|
|
String frequency = "" + rand(0, 999) + "." + rand(0, 999) + "." + rand(0, 999);
|
|
|
|
setObjVar(remoteTrigger, stealth.TRAP_FREQUENCY, frequency);
|
|
setObjVar(trap, stealth.TRAP_FREQUENCY, frequency);
|
|
setObjVar(trap, stealth.TRAP_MY_PROXIMITY_TRIGGER, remoteTrigger);
|
|
setObjVar(remoteTrigger, stealth.TRAP_MY_TRAP, trap);
|
|
sendSystemMessage(player, new string_id("spam", "trap_keyed_remote"));
|
|
setObjVar(trap, "armed", time);
|
|
setObjVar(remoteTrigger, "armed", true);
|
|
break;
|
|
case TRIGGER_TYPE_PROXIMITY:
|
|
dictionary timeArmed = new dictionary();
|
|
timeArmed.put("armed", time);
|
|
messageTo(trap, "msgArmProximity", timeArmed, 0, false);
|
|
break;
|
|
}
|
|
playClientEffectObj(trap, "appearance/pt_trap_reticule.prt", trap, "", null, "trapReticle");
|
|
doAnimationAction(player, "point_down");
|
|
setOwner(trap, player);
|
|
setObjVar(trap, TRAP_FACTION, pvpGetAlignedFaction(player));
|
|
setObjVar(trap, TRAP_PVP_TYPE, pvpGetType(player));
|
|
setObjVar(trap, TRAP_DIFFICULTY, getEnhancedSkillStatisticModifier(player, "ranger_trap"));
|
|
setObjVar(trap, TRAP_LEVEL, getLevel(player));
|
|
if (hasObjVar(trap, "concealable"))
|
|
{
|
|
if (buff.hasBuff(player, "conceal_trap"))
|
|
{
|
|
stealth.concealDevice(player, trap);
|
|
}
|
|
}
|
|
setWeaponMinDamage(trap, 1);
|
|
setWeaponMaxDamage(trap, 1);
|
|
setWeaponAttackSpeed(trap, 0.25f);
|
|
weapons.setWeaponData(trap);
|
|
messageTo(trap, "msgSelfDestructTimeout", null, TRAP_SELF_DESTRUCT_TIMEOUT, false);
|
|
count--;
|
|
if (count < 1)
|
|
{
|
|
destroyObject(invTrap);
|
|
}
|
|
else
|
|
{
|
|
setCount(invTrap, count);
|
|
}
|
|
return true;
|
|
}
|
|
public static obj_id getTrigger(obj_id trap) throws InterruptedException
|
|
{
|
|
if (hasObjVar(trap, TRAP_MY_PROXIMITY_TRIGGER))
|
|
{
|
|
return getObjIdObjVar(trap, TRAP_MY_PROXIMITY_TRIGGER);
|
|
}
|
|
obj_id[] stuff = getContents(trap);
|
|
for (obj_id aStuff : stuff) {
|
|
if (hasScript(aStuff, "systems.skills.stealth.traptrigger")) {
|
|
return aStuff;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
public static boolean doTheftLoot(obj_id thief, obj_id mark) throws InterruptedException
|
|
{
|
|
obj_id thiefInventory = utils.getInventoryContainer(thief);
|
|
if (getVolumeFree(thiefInventory) < 1)
|
|
{
|
|
sendSystemMessage(thief, new string_id("spam", "cant_steal_inventory_full"));
|
|
return false;
|
|
}
|
|
int stealFlags = STEAL_CREDITS | STEAL_LOOT;
|
|
if (utils.hasScriptVar(mark, STEAL_TYPE))
|
|
{
|
|
stealFlags = utils.getIntScriptVar(mark, STEAL_TYPE);
|
|
}
|
|
if (isPlayer(mark))
|
|
{
|
|
stealFlags = STEAL_MARKED_ITEMS;
|
|
}
|
|
else if (hasStealingLootTableEntry(mark))
|
|
{
|
|
stealFlags |= STEAL_STEALING_TABLE;
|
|
}
|
|
Vector types = new Vector();
|
|
if (isFlagSet(stealFlags, STEAL_CREDITS))
|
|
{
|
|
types.add(STEAL_CREDITS);
|
|
}
|
|
if (isFlagSet(stealFlags, STEAL_LOOT))
|
|
{
|
|
types.add(STEAL_LOOT);
|
|
}
|
|
if (isFlagSet(stealFlags, STEAL_TEMPLATE))
|
|
{
|
|
types.add(STEAL_TEMPLATE);
|
|
}
|
|
if (isFlagSet(stealFlags, STEAL_MARKED_ITEMS))
|
|
{
|
|
types.add(STEAL_MARKED_ITEMS);
|
|
}
|
|
if (isFlagSet(stealFlags, STEAL_STEALING_TABLE))
|
|
{
|
|
types.add(STEAL_STEALING_TABLE);
|
|
}
|
|
boolean gotSomething = false;
|
|
while (types.size() > 0 && !gotSomething)
|
|
{
|
|
int roll = rand(0, types.size() - 1);
|
|
int flag = (Integer) types.get(roll);
|
|
int markLevel = getLevel(mark);
|
|
int thiefLevel = getLevel(thief);
|
|
int stealRoll = rand(1, 100);
|
|
if (STEAL_FAIL_CHANCE < stealRoll)
|
|
{
|
|
switch (flag)
|
|
{
|
|
case STEAL_CREDITS:
|
|
if (isPlayer(mark))
|
|
{
|
|
break;
|
|
}
|
|
int amt = (int)(getNpcCash(mark) * .2f);
|
|
if (amt > 0)
|
|
{
|
|
dictionary d = new dictionary();
|
|
d.put(money.DICT_AMOUNT, amt);
|
|
utils.moneyInMetric(mark, money.ACCT_NPC_LOOT, amt);
|
|
gotSomething = true;
|
|
}
|
|
break;
|
|
case STEAL_LOOT:
|
|
if (isPlayer(mark))
|
|
{
|
|
break;
|
|
}
|
|
int lootRoll = rand(1, 100);
|
|
if (lootRoll >= STEAL_RARE_ITEM)
|
|
{
|
|
if (thiefLevel <= (markLevel + 10))
|
|
{
|
|
if (!hasCompletedCollection(thief, "spy_unarmed_01"))
|
|
{
|
|
long slotValueOne = getCollectionSlotValue(thief, "col_spy_unarmed_01_01");
|
|
long slotValueTwo = getCollectionSlotValue(thief, "col_spy_unarmed_01_02");
|
|
long slotValueThree = getCollectionSlotValue(thief, "col_spy_unarmed_01_03");
|
|
long slotValueFour = getCollectionSlotValue(thief, "col_spy_unarmed_01_04");
|
|
if (slotValueOne == 0)
|
|
{
|
|
modifyCollectionSlotValue(thief, "col_spy_unarmed_01_01", 1);
|
|
}
|
|
else if (slotValueTwo == 0)
|
|
{
|
|
modifyCollectionSlotValue(thief, "col_spy_unarmed_01_02", 1);
|
|
}
|
|
else if (slotValueThree == 0)
|
|
{
|
|
modifyCollectionSlotValue(thief, "col_spy_unarmed_01_03", 1);
|
|
}
|
|
else if (slotValueFour == 0)
|
|
{
|
|
modifyCollectionSlotValue(thief, "col_spy_unarmed_01_04", 1);
|
|
}
|
|
}
|
|
gotSomething = loot.generateTheftLootRare(thiefInventory, mark, 1, thief);
|
|
break;
|
|
}
|
|
gotSomething = loot.generateTheftLoot(thiefInventory, mark, STEAL_LOOT_CHANCE_MOD, 1);
|
|
break;
|
|
}
|
|
if (lootRoll >= STEAL_REGULAR_ITEM && lootRoll < STEAL_RARE_ITEM)
|
|
{
|
|
if (thiefLevel <= (markLevel + 10))
|
|
{
|
|
boolean gotCollectionItem;
|
|
gotCollectionItem = loot.addCollectionLoot(mark, true, thief);
|
|
gotSomething = gotCollectionItem;
|
|
if (!gotCollectionItem)
|
|
{
|
|
gotSomething = loot.generateTheftLoot(thiefInventory, mark, STEAL_LOOT_CHANCE_MOD, 1);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
gotSomething = loot.generateTheftLoot(thiefInventory, mark, STEAL_LOOT_CHANCE_MOD, 1);
|
|
break;
|
|
}
|
|
}
|
|
if (lootRoll < STEAL_REGULAR_ITEM)
|
|
{
|
|
gotSomething = loot.generateTheftLoot(thiefInventory, mark, STEAL_LOOT_CHANCE_MOD, 1);
|
|
break;
|
|
}
|
|
break;
|
|
case STEAL_TEMPLATE:
|
|
Vector itms = getStealableTemplates(mark);
|
|
if (itms.size() < 1)
|
|
{
|
|
break;
|
|
}
|
|
String templateLoot = (String)itms.get(rand(0, itms.size() - 1));
|
|
if (templateLoot == null || templateLoot.length() < 1)
|
|
{
|
|
break;
|
|
}
|
|
obj_id templateObj = null;
|
|
if (templateLoot.startsWith("static:"))
|
|
{
|
|
java.util.StringTokenizer st = new java.util.StringTokenizer(templateLoot, ":");
|
|
if (st.countTokens() == 2)
|
|
{
|
|
templateObj = static_item.createNewItemFunction(templateLoot, thiefInventory);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
templateObj = createObjectOverloaded(templateLoot, thiefInventory);
|
|
}
|
|
gotSomething = templateObj != null;
|
|
if (gotSomething)
|
|
{
|
|
utils.setScriptVar(thiefInventory, "theft_in_progress", 1);
|
|
loot.notifyThiefOfItemStolen(thiefInventory, templateObj);
|
|
}
|
|
break;
|
|
case STEAL_MARKED_ITEMS:
|
|
obj_id[] stuff = utils.getFilteredPlayerContents(mark);
|
|
Vector eligibleItems = new Vector();
|
|
for (obj_id aStuff : stuff) {
|
|
if (isItemStealable(aStuff)) {
|
|
eligibleItems.add(aStuff);
|
|
}
|
|
}
|
|
if (eligibleItems.size() < 1)
|
|
{
|
|
break;
|
|
}
|
|
obj_id markedObj = (obj_id)eligibleItems.get(rand(0, eligibleItems.size() - 1));
|
|
gotSomething = putIn(markedObj, thiefInventory);
|
|
if (gotSomething)
|
|
{
|
|
CustomerServiceLog("stealing", "%TU stole an item (" + markedObj + " - " + getName(markedObj) + ") from player %TT", thief, mark);
|
|
utils.setScriptVar(thiefInventory, "theft_in_progress", 1);
|
|
loot.notifyThiefOfItemStolen(thiefInventory, markedObj);
|
|
}
|
|
break;
|
|
case STEAL_STEALING_TABLE:
|
|
String tableTemplate = getStealableTemplateFromTable(mark);
|
|
if (tableTemplate == null || tableTemplate.length() < 1)
|
|
{
|
|
break;
|
|
}
|
|
obj_id tableObj = null;
|
|
if (tableTemplate.startsWith("static:"))
|
|
{
|
|
java.util.StringTokenizer st = new java.util.StringTokenizer(tableTemplate, ":");
|
|
if (st.countTokens() == 2)
|
|
{
|
|
tableObj = static_item.createNewItemFunction(tableTemplate, thiefInventory);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
tableObj = createObjectOverloaded(tableTemplate, thiefInventory);
|
|
}
|
|
gotSomething = tableObj != null;
|
|
if (gotSomething)
|
|
{
|
|
utils.setScriptVar(thiefInventory, "theft_in_progress", 1);
|
|
loot.notifyThiefOfItemStolen(thiefInventory, tableObj);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
stealFlags &= ~flag;
|
|
types.removeElementAt(roll);
|
|
}
|
|
if (!isPlayer(mark))
|
|
{
|
|
utils.setScriptVar(mark, STEAL_TYPE, stealFlags);
|
|
}
|
|
return gotSomething;
|
|
}
|
|
public static boolean hasStealingLootTableEntry(obj_id mark) throws InterruptedException
|
|
{
|
|
String name = getCreatureName(mark);
|
|
String type = loot.getCreatureType(name);
|
|
String table = "datatables/loot/stealing_loot.iff";
|
|
int row = dataTableSearchColumnForInt(getStringCrc(type), "npc_type", table);
|
|
return row >= 0;
|
|
}
|
|
public static String getStealableTemplateFromTable(obj_id mark) throws InterruptedException
|
|
{
|
|
Vector stuff = new Vector();
|
|
Vector weights = new Vector();
|
|
String name = getCreatureName(mark);
|
|
String table = "datatables/loot/stealing_loot.iff";
|
|
int row = dataTableSearchColumnForInt(getStringCrc(name), "npc_type", table);
|
|
if (row < 0)
|
|
{
|
|
return null;
|
|
}
|
|
int rows = dataTableGetNumRows(table);
|
|
while (true)
|
|
{
|
|
stuff.add(dataTableGetString(table, row, "stealableObjects"));
|
|
weights.add(dataTableGetInt(table, row, "weight"));
|
|
row++;
|
|
if (row >= rows || dataTableGetInt(table, row, "npc_type") != 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
int total = 0;
|
|
int[] weightArray = new int[weights.size()];
|
|
for (int i = 0; i < weightArray.length; i++)
|
|
{
|
|
weightArray[i] = (Integer) weights.get(i);
|
|
total += weightArray[i];
|
|
}
|
|
if (total < 1)
|
|
{
|
|
total = 1;
|
|
}
|
|
int roll = rand(1, total);
|
|
int idx = -1;
|
|
int low_range = 0;
|
|
for (int j = 0; j < weightArray.length; j++)
|
|
{
|
|
int high_range = low_range + weightArray[j];
|
|
if (roll > low_range && roll <= high_range)
|
|
{
|
|
idx = j;
|
|
break;
|
|
}
|
|
low_range = high_range;
|
|
}
|
|
if (idx < stuff.size())
|
|
{
|
|
return (String)stuff.get(idx);
|
|
}
|
|
return (String)stuff.get(rand(0, stuff.size() - 1));
|
|
}
|
|
public static void flagItemAsStealable(obj_id item) throws InterruptedException
|
|
{
|
|
setObjVar(item, STEAL_ITEM_IS_STEALABLE, 1);
|
|
}
|
|
public static boolean isItemStealable(obj_id item) throws InterruptedException
|
|
{
|
|
return hasObjVar(item, STEAL_ITEM_IS_STEALABLE);
|
|
}
|
|
public static void unflagItemAsStealable(obj_id item) throws InterruptedException
|
|
{
|
|
removeObjVar(item, STEAL_ITEM_IS_STEALABLE);
|
|
}
|
|
public static void addStealableTemplate(obj_id mark, String template) throws InterruptedException
|
|
{
|
|
Vector itms = getStealableTemplates(mark);
|
|
itms.add(template);
|
|
utils.setResizeableBatchObjVar(mark, STEAL_TEMPLATE_ITEMS, itms);
|
|
}
|
|
public static Vector getStealableTemplates(obj_id mark) throws InterruptedException
|
|
{
|
|
return utils.getResizeableStringBatchObjVar(mark, STEAL_TEMPLATE_ITEMS);
|
|
}
|
|
public static int getNpcCash(obj_id mark) throws InterruptedException
|
|
{
|
|
String mobType = ai_lib.getCreatureName(mark);
|
|
if (mobType == null)
|
|
{
|
|
return 0;
|
|
}
|
|
int level = ai_lib.getLevel(mark);
|
|
int cash = loot.getCashForLevel(mobType, level);
|
|
if (cash > 0)
|
|
{
|
|
return cash;
|
|
}
|
|
cash = rand(1, 10);
|
|
cash = cash * level;
|
|
return cash;
|
|
}
|
|
public static boolean canSteal(obj_id thief, obj_id mark) throws InterruptedException
|
|
{
|
|
if (!pvpCanAttack(thief, mark))
|
|
{
|
|
sendSystemMessage(thief, new string_id("spam", "steal_cant_pvp"));
|
|
return false;
|
|
}
|
|
if (!ai_lib.isHumanoid(mark))
|
|
{
|
|
sendSystemMessage(thief, new string_id("spam", "steal_not_humanoid"));
|
|
return false;
|
|
}
|
|
if (utils.hasScriptVar(mark, STEAL_TYPE))
|
|
{
|
|
int stealFlags = utils.getIntScriptVar(mark, STEAL_TYPE);
|
|
if (stealFlags == STEAL_NOTHING)
|
|
{
|
|
sendSystemMessage(thief, new string_id("spam", "stolen_got_nothing"));
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
public static boolean steal(obj_id thief, obj_id mark) throws InterruptedException
|
|
{
|
|
if (!luck.isLucky(thief, 0.01f))
|
|
{
|
|
if (isCoughtWhileStealing(thief, mark) || luck.isLucky(mark, 0.01f))
|
|
{
|
|
sendSystemMessageTestingOnly(thief, "STEALING CHECK FAILED: CAUGHT");
|
|
showFlyText(thief, new string_id("spam", "stealing_cought"), 1.5f, colors.TOMATO);
|
|
sendSystemMessage(thief, new string_id("spam", "stolen_cought"));
|
|
String invis = getInvisBuff(thief);
|
|
if (invis != null && invis.length() > 0)
|
|
{
|
|
buff.removeBuff(thief, invis);
|
|
}
|
|
if (isPlayer(mark))
|
|
{
|
|
prose_package pp = prose.getPackage(new string_id("spam", "almost_got_item_stolen"), thief);
|
|
sendSystemMessageProse(mark, pp);
|
|
}
|
|
else
|
|
{
|
|
startCombat(mark, thief);
|
|
startCombat(thief, mark);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
showFlyTextPrivate(thief, thief, new string_id("spam", "stealin_on"), 1.5f, colors.TOMATO);
|
|
if (!doTheftLoot(thief, mark)) {
|
|
sendSystemMessage(thief, new string_id("spam", "stolen_nothing"));
|
|
}
|
|
return true;
|
|
}
|
|
public static boolean isCoughtWhileStealing(obj_id thief, obj_id mark) throws InterruptedException
|
|
{
|
|
return passiveDetectHiddenTarget(thief, mark, PASSIVE_BREACH_NEAR);
|
|
}
|
|
public static boolean witnessModifiedSkillCheck(obj_id player, String skillMod, float distance, int witnessPenalty, int skillModMod) throws InterruptedException
|
|
{
|
|
int skill = getEnhancedSkillStatisticModifier(player, skillMod) + skillModMod;
|
|
if (skill < 0)
|
|
{
|
|
skill = 0;
|
|
}
|
|
obj_id[] stuff = getCreaturesInRange(player, distance);
|
|
int cnt = 0;
|
|
int sGuildId = getGuildId(player);
|
|
if (stuff.length > 0)
|
|
{
|
|
for (obj_id aStuff : stuff) {
|
|
if (ai_lib.isHumanoid(aStuff)) {
|
|
boolean isInSameGuild = (sGuildId != 0) && (getGuildId(aStuff) == sGuildId);
|
|
if (!isInSameGuild && !group.inSameGroup(player, aStuff)) {
|
|
skill -= witnessPenalty;
|
|
}
|
|
}
|
|
}
|
|
float rslt = (1 / (1 + ((skill + 10) / 10)));
|
|
return (rand(0, 1f) > rslt);
|
|
}
|
|
return true;
|
|
}
|
|
public static void invisBuffRemoved(obj_id player, String sbuff) throws InterruptedException
|
|
{
|
|
if (buff.hasBuff(player, BUFF_NO_BREAK_INVIS))
|
|
{
|
|
return;
|
|
}
|
|
if (buff.hasBuff(player, "sp_burst_shadows"))
|
|
{
|
|
buff.removeBuff(player, "sp_burst_shadows");
|
|
}
|
|
_makeVisible(player, new string_id("spam", "stealthoff"), null);
|
|
messageTo(player, "addAppearanceItemEffect", null, 1, false);
|
|
}
|
|
public static void OnLocomotionChange(obj_id player, int oldLoco, int newLoco) throws InterruptedException
|
|
{
|
|
String invis = getInvisBuff(player);
|
|
if (invis == null)
|
|
{
|
|
return;
|
|
}
|
|
int pri = buff.getPriority(invis);
|
|
if (pri < MIN_MOVEMENT_PRIORITY)
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "posturechangereveal"));
|
|
buff.removeBuff(player, invis);
|
|
}
|
|
}
|
|
public static void OnPostureChanged(obj_id player, int before, int after) throws InterruptedException
|
|
{
|
|
String invis = getInvisBuff(player);
|
|
if (invis == null)
|
|
{
|
|
return;
|
|
}
|
|
int pri = buff.getPriority(invis);
|
|
if (pri < MIN_POSTURE_CHANGE_PRIORITY)
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "posturechangereveal"));
|
|
buff.removeBuff(player, invis);
|
|
}
|
|
}
|
|
public static int getApplicableInvisSkillMod(obj_id thing, String buffName) throws InterruptedException
|
|
{
|
|
String modName = "camouflage";
|
|
switch (getStringCrc(buffName))
|
|
{
|
|
case (-879194497):
|
|
case (1252380095):
|
|
modName = "camouflage";
|
|
break;
|
|
case (815407714):
|
|
case (-1923109470):
|
|
break;
|
|
case (-121504680):
|
|
modName = "cover";
|
|
break;
|
|
case (1206342977):
|
|
case (-50098035):
|
|
modName = "stealth";
|
|
break;
|
|
case (342850470):
|
|
modName = "";
|
|
break;
|
|
}
|
|
int mod = 0;
|
|
if (modName.length() > 0)
|
|
{
|
|
mod = getEnhancedSkillStatisticModifierUncapped(thing, modName);
|
|
if (modName.equals("camouflage"))
|
|
{
|
|
mod += getEnhancedSkillStatisticModifierUncapped(thing, "stealth");
|
|
}
|
|
}
|
|
return mod;
|
|
}
|
|
public static int getApplicableInvisSkillMod(obj_id thing) throws InterruptedException
|
|
{
|
|
int mod = 0;
|
|
if (isPlayer(thing))
|
|
{
|
|
String invis = getInvisBuff(thing);
|
|
if (invis == null || invis.length() < 1)
|
|
{
|
|
return mod;
|
|
}
|
|
mod = getApplicableInvisSkillMod(thing, invis);
|
|
}
|
|
else
|
|
{
|
|
mod = getIntObjVar(thing, "camouflageMod");
|
|
}
|
|
return mod;
|
|
}
|
|
public static float getDetectChance(obj_id target, obj_id detector, float baseChanceToDetect) throws InterruptedException
|
|
{
|
|
String invis = getInvisBuff(target);
|
|
if (beast_lib.isBeast(target))
|
|
{
|
|
invis = "invis";
|
|
}
|
|
if (invis != null && invis.length() > 0)
|
|
{
|
|
if (buff.getPriority(invis) > MAX_INVIS_BUFF_TO_DETECT)
|
|
{
|
|
return 0.0f;
|
|
}
|
|
if (invis.startsWith("invis_sp_buff_invis_notrace"))
|
|
{
|
|
return 0.0f;
|
|
}
|
|
}
|
|
float finalChanceToDetect = 0.0f;
|
|
int stealtherLevel = getLevel(target);
|
|
int detectorLevel = getLevel(detector);
|
|
float levelChanceToDetectMod = 0.0f;
|
|
if (stealtherLevel > detectorLevel)
|
|
{
|
|
float levelDiff = stealtherLevel - detectorLevel;
|
|
if (baseChanceToDetect > 30)
|
|
{
|
|
levelChanceToDetectMod = (levelDiff * 5.0f);
|
|
}
|
|
else
|
|
{
|
|
levelChanceToDetectMod = (levelDiff * 1.5f);
|
|
}
|
|
finalChanceToDetect = baseChanceToDetect - levelChanceToDetectMod;
|
|
}
|
|
if (stealtherLevel < detectorLevel)
|
|
{
|
|
float levelDiff = detectorLevel - stealtherLevel;
|
|
levelChanceToDetectMod = (levelDiff * 2.5f);
|
|
finalChanceToDetect = baseChanceToDetect + levelChanceToDetectMod;
|
|
}
|
|
if (stealtherLevel == detectorLevel)
|
|
{
|
|
finalChanceToDetect = baseChanceToDetect;
|
|
}
|
|
float modChanceToDetectMod = 0.0f;
|
|
int stealtherSkillMod = getApplicableInvisSkillMod(target);
|
|
if (beast_lib.isBeast(target))
|
|
{
|
|
obj_id master = getMaster(target);
|
|
if (isIdValid(master) && exists(master))
|
|
{
|
|
stealtherSkillMod = getApplicableInvisSkillMod(master);
|
|
}
|
|
}
|
|
int detectorSkillMod = getEnhancedSkillStatisticModifierUncapped(detector, "detect_hidden");
|
|
if (stealtherSkillMod > detectorSkillMod)
|
|
{
|
|
float modDiff = (stealtherSkillMod - detectorSkillMod);
|
|
modChanceToDetectMod = modDiff / 9.0f;
|
|
finalChanceToDetect = finalChanceToDetect - modChanceToDetectMod;
|
|
}
|
|
if (stealtherSkillMod < detectorSkillMod)
|
|
{
|
|
float modDiff = (detectorSkillMod - stealtherSkillMod);
|
|
modChanceToDetectMod = modDiff / 4.0f;
|
|
finalChanceToDetect = finalChanceToDetect + modChanceToDetectMod;
|
|
}
|
|
assert invis != null;
|
|
if (invis.startsWith("invis_forceCloak") || (invis.startsWith("invis_fs_buff_invis")))
|
|
{
|
|
finalChanceToDetect = (finalChanceToDetect - 10.0f);
|
|
}
|
|
if (!isPlayer(detector))
|
|
{
|
|
String name = getCreatureName(detector);
|
|
int difficultyClass = dataTableGetInt("datatables/mob/creatures.iff", name, "difficultyClass");
|
|
if (difficultyClass == 1)
|
|
{
|
|
finalChanceToDetect = (finalChanceToDetect + 5.0f);
|
|
}
|
|
if (difficultyClass == 2)
|
|
{
|
|
finalChanceToDetect = (finalChanceToDetect + 10.0f);
|
|
}
|
|
}
|
|
if (finalChanceToDetect > MAX_CHANCE_TO_DETECT_HIDDEN)
|
|
{
|
|
finalChanceToDetect = MAX_CHANCE_TO_DETECT_HIDDEN;
|
|
}
|
|
if (finalChanceToDetect < MIN_CHANCE_TO_DETECT_HIDDEN)
|
|
{
|
|
if (isPlayer(detector))
|
|
{
|
|
finalChanceToDetect = MIN_CHANCE_TO_DETECT_HIDDEN;
|
|
}
|
|
}
|
|
return finalChanceToDetect;
|
|
}
|
|
public static float getDetectChanceWithDetailedOutput(obj_id target, obj_id detector, float baseChanceToDetect, obj_id objectToReceiveDetailedOutput) throws InterruptedException
|
|
{
|
|
String invis = getInvisBuff(target);
|
|
if (invis != null && invis.length() > 0)
|
|
{
|
|
sendConsoleMessage(objectToReceiveDetailedOutput, "passiveDetectInfo: stealther=" + target + ", detector=" + detector + ", baseChanceToDetect=" + baseChanceToDetect + ", stealther invisBuff=" + invis);
|
|
if (buff.getPriority(invis) > MAX_INVIS_BUFF_TO_DETECT)
|
|
{
|
|
sendConsoleMessage(objectToReceiveDetailedOutput, "passiveDetectInfo: buff.getPriority(stealther invisBuff)=" + buff.getPriority(invis) + " which is > " + MAX_INVIS_BUFF_TO_DETECT + " so setting finalChanceToDetect to 0.0");
|
|
return 0.0f;
|
|
}
|
|
if (invis.startsWith("invis_sp_buff_invis_notrace"))
|
|
{
|
|
sendConsoleMessage(objectToReceiveDetailedOutput, "passiveDetectInfo: stealther invisBuff is invis_sp_buff_invis_notrace* so setting finalChanceToDetect to 0.0");
|
|
return 0.0f;
|
|
}
|
|
}
|
|
float finalChanceToDetect = 0.0f;
|
|
int stealtherLevel = getLevel(target);
|
|
int detectorLevel = getLevel(detector);
|
|
sendConsoleMessage(objectToReceiveDetailedOutput, "passiveDetectInfo: stealtherLevel=" + stealtherLevel + ", detectorLevel=" + detectorLevel);
|
|
float levelChanceToDetectMod = 0.0f;
|
|
if (stealtherLevel > detectorLevel)
|
|
{
|
|
float levelDiff = stealtherLevel - detectorLevel;
|
|
if (baseChanceToDetect > 30)
|
|
{
|
|
levelChanceToDetectMod = (levelDiff * 5.0f);
|
|
sendConsoleMessage(objectToReceiveDetailedOutput, "passiveDetectInfo: stealtherLevel > detectorLevel, levelDiff=" + levelDiff + ", baseChanceToDetect > 30, levelChanceToDetectMod (levelDiff * 5.0f)=" + levelChanceToDetectMod);
|
|
}
|
|
else
|
|
{
|
|
levelChanceToDetectMod = (levelDiff * 1.5f);
|
|
sendConsoleMessage(objectToReceiveDetailedOutput, "passiveDetectInfo: stealtherLevel > detectorLevel, levelDiff=" + levelDiff + ", baseChanceToDetect <= 30, levelChanceToDetectMod (levelDiff * 1.5f)=" + levelChanceToDetectMod);
|
|
}
|
|
finalChanceToDetect = baseChanceToDetect - levelChanceToDetectMod;
|
|
sendConsoleMessage(objectToReceiveDetailedOutput, "passiveDetectInfo: stealtherLevel > detectorLevel, finalChanceToDetect (baseChanceToDetect - levelChanceToDetectMod)=" + finalChanceToDetect);
|
|
}
|
|
if (stealtherLevel < detectorLevel)
|
|
{
|
|
float levelDiff = detectorLevel - stealtherLevel;
|
|
levelChanceToDetectMod = (levelDiff * 2.5f);
|
|
finalChanceToDetect = baseChanceToDetect + levelChanceToDetectMod;
|
|
sendConsoleMessage(objectToReceiveDetailedOutput, "passiveDetectInfo: stealtherLevel < detectorLevel, levelDiff=" + levelDiff + ", levelChanceToDetectMod (levelDiff * 2.5f)=" + levelChanceToDetectMod + ", finalChanceToDetect (baseChanceToDetect + levelChanceToDetectMod)=" + finalChanceToDetect);
|
|
}
|
|
if (stealtherLevel == detectorLevel)
|
|
{
|
|
finalChanceToDetect = baseChanceToDetect;
|
|
sendConsoleMessage(objectToReceiveDetailedOutput, "passiveDetectInfo: stealtherLevel = detectorLevel, finalChanceToDetect (baseChanceToDetect)=" + finalChanceToDetect);
|
|
}
|
|
float modChanceToDetectMod = 0.0f;
|
|
int stealtherSkillMod = getApplicableInvisSkillMod(target);
|
|
int detectorSkillMod = getEnhancedSkillStatisticModifierUncapped(detector, "detect_hidden");
|
|
sendConsoleMessage(objectToReceiveDetailedOutput, "passiveDetectInfo: stealtherSkillMod=" + stealtherSkillMod + ", detectorSkillMod (detect_hidden)=" + detectorSkillMod);
|
|
if (stealtherSkillMod > detectorSkillMod)
|
|
{
|
|
float modDiff = (stealtherSkillMod - detectorSkillMod);
|
|
modChanceToDetectMod = modDiff / 9.0f;
|
|
finalChanceToDetect = finalChanceToDetect - modChanceToDetectMod;
|
|
sendConsoleMessage(objectToReceiveDetailedOutput, "passiveDetectInfo: stealtherSkillMod > detectorSkillMod, modDiff=" + modDiff + ", modChanceToDetectMod (modDiff / 9.0f)=" + modChanceToDetectMod + ", finalChanceToDetect (finalChanceToDetect - modChanceToDetectMod)=" + finalChanceToDetect);
|
|
}
|
|
if (stealtherSkillMod < detectorSkillMod)
|
|
{
|
|
float modDiff = (detectorSkillMod - stealtherSkillMod);
|
|
modChanceToDetectMod = modDiff / 4.0f;
|
|
finalChanceToDetect = finalChanceToDetect + modChanceToDetectMod;
|
|
sendConsoleMessage(objectToReceiveDetailedOutput, "passiveDetectInfo: stealtherSkillMod < detectorSkillMod, modDiff=" + modDiff + ", modChanceToDetectMod (modDiff / 4.0f)=" + modChanceToDetectMod + ", finalChanceToDetect (finalChanceToDetect + modChanceToDetectMod)=" + finalChanceToDetect);
|
|
}
|
|
assert invis != null;
|
|
if (invis.startsWith("invis_forceCloak") || (invis.startsWith("invis_fs_buff_invis")))
|
|
{
|
|
finalChanceToDetect = (finalChanceToDetect - 10.0f);
|
|
sendConsoleMessage(objectToReceiveDetailedOutput, "passiveDetectInfo: Jedi with invis_forceCloak* or invis_fs_buff_invis*, finalChanceToDetect (finalChanceToDetect - 10.0f)=" + finalChanceToDetect);
|
|
}
|
|
if (!isPlayer(detector))
|
|
{
|
|
String name = getCreatureName(detector);
|
|
int difficultyClass = dataTableGetInt("datatables/mob/creatures.iff", name, "difficultyClass");
|
|
if (difficultyClass == 1)
|
|
{
|
|
finalChanceToDetect = (finalChanceToDetect + 5.0f);
|
|
sendConsoleMessage(objectToReceiveDetailedOutput, "passiveDetectInfo: detector (" + name + ", difficultyClass=" + difficultyClass + ") is elite NPC, finalChanceToDetect (finalChanceToDetect + 5.0f)=" + finalChanceToDetect);
|
|
}
|
|
if (difficultyClass == 2)
|
|
{
|
|
finalChanceToDetect = (finalChanceToDetect + 10.0f);
|
|
sendConsoleMessage(objectToReceiveDetailedOutput, "passiveDetectInfo: detector (" + name + ", difficultyClass=" + difficultyClass + ") is boss NPC, finalChanceToDetect (finalChanceToDetect + 10.0f)=" + finalChanceToDetect);
|
|
}
|
|
}
|
|
if (finalChanceToDetect > MAX_CHANCE_TO_DETECT_HIDDEN)
|
|
{
|
|
finalChanceToDetect = MAX_CHANCE_TO_DETECT_HIDDEN;
|
|
sendConsoleMessage(objectToReceiveDetailedOutput, "passiveDetectInfo: finalChanceToDetect > " + MAX_CHANCE_TO_DETECT_HIDDEN + " so finalChanceToDetect set to " + finalChanceToDetect);
|
|
}
|
|
if (finalChanceToDetect < MIN_CHANCE_TO_DETECT_HIDDEN)
|
|
{
|
|
if (isPlayer(detector))
|
|
{
|
|
finalChanceToDetect = MIN_CHANCE_TO_DETECT_HIDDEN;
|
|
sendConsoleMessage(objectToReceiveDetailedOutput, "passiveDetectInfo: finalChanceToDetect < " + MIN_CHANCE_TO_DETECT_HIDDEN + " and detector is player so finalChanceToDetect set to " + finalChanceToDetect);
|
|
}
|
|
}
|
|
sendConsoleMessage(objectToReceiveDetailedOutput, "passiveDetectInfo: ****FINAL CALCULATED*** finalChanceToDetect=" + finalChanceToDetect);
|
|
return finalChanceToDetect;
|
|
}
|
|
public static boolean activeDetectHiddenTarget(obj_id target, obj_id detector, float baseChanceToDetect) throws InterruptedException
|
|
{
|
|
float finalChanceToDetect = getDetectChance(target, detector, baseChanceToDetect);
|
|
float roll = rand(0f, 100f);
|
|
return (roll < finalChanceToDetect);
|
|
}
|
|
public static boolean passiveDetectHiddenTarget(obj_id target, obj_id detector, int volume) throws InterruptedException
|
|
{
|
|
if (isPlayer(detector))
|
|
{
|
|
if (!pvpCanAttack(detector, target))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!ai_lib.isAggroToward(detector, target))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
float baseChanceToDetect = PASSIVE_DETECT_CHANCE_MOB;
|
|
if (volume == PASSIVE_BREACH_FAR)
|
|
{
|
|
baseChanceToDetect = PASSIVE_DETECT_CHANCE_FAR;
|
|
}
|
|
if (volume == PASSIVE_BREACH_NEAR)
|
|
{
|
|
baseChanceToDetect = PASSIVE_DETECT_CHANCE_NEAR;
|
|
}
|
|
float finalChanceToDetect = getDetectChance(target, detector, baseChanceToDetect);
|
|
float roll = rand(0.0f, 100.0f);
|
|
return (roll < finalChanceToDetect);
|
|
}
|
|
public static boolean passiveDetectHiddenTargetWithDetailedOutput(obj_id target, obj_id detector, int volume, obj_id objectToReceiveDetailedOutput) throws InterruptedException
|
|
{
|
|
sendConsoleMessage(objectToReceiveDetailedOutput, "passiveDetectInfo: stealther=" + target + ", detector=" + detector + ", volume=" + volume);
|
|
if (isPlayer(detector))
|
|
{
|
|
if (!pvpCanAttack(detector, target))
|
|
{
|
|
sendConsoleMessage(objectToReceiveDetailedOutput, "passiveDetectInfo: stealther=" + target + ", detector=" + detector + ", volume=" + volume + ", isPlayer(detector) and !pvpCanAttack(detector, stealther) so returning detection FAIL");
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!ai_lib.isAggroToward(detector, target))
|
|
{
|
|
sendConsoleMessage(objectToReceiveDetailedOutput, "passiveDetectInfo: stealther=" + target + ", detector=" + detector + ", volume=" + volume + ", !isPlayer(detector) and !ai_lib.isAggroToward(detector, stealther) so returning detection FAIL");
|
|
return false;
|
|
}
|
|
}
|
|
float baseChanceToDetect = PASSIVE_DETECT_CHANCE_MOB;
|
|
sendConsoleMessage(objectToReceiveDetailedOutput, "passiveDetectInfo: setting baseChanceToDetect to default value of PASSIVE_DETECT_CHANCE_MOB(" + baseChanceToDetect + ")");
|
|
if (volume == PASSIVE_BREACH_FAR)
|
|
{
|
|
baseChanceToDetect = PASSIVE_DETECT_CHANCE_FAR;
|
|
sendConsoleMessage(objectToReceiveDetailedOutput, "passiveDetectInfo: volume is PASSIVE_BREACH_FAR so setting baseChanceToDetect to PASSIVE_DETECT_CHANCE_FAR(" + baseChanceToDetect + ")");
|
|
}
|
|
if (volume == PASSIVE_BREACH_NEAR)
|
|
{
|
|
baseChanceToDetect = PASSIVE_DETECT_CHANCE_NEAR;
|
|
sendConsoleMessage(objectToReceiveDetailedOutput, "passiveDetectInfo: volume is PASSIVE_BREACH_NEAR so setting baseChanceToDetect to PASSIVE_DETECT_CHANCE_NEAR(" + baseChanceToDetect + ")");
|
|
}
|
|
float finalChanceToDetect = getDetectChanceWithDetailedOutput(target, detector, baseChanceToDetect, objectToReceiveDetailedOutput);
|
|
float roll = rand(0.0f, 100.0f);
|
|
if (roll < finalChanceToDetect)
|
|
{
|
|
sendConsoleMessage(objectToReceiveDetailedOutput, "passiveDetectInfo: getDetectChanceWithDetailedOutput() returned finalChanceToDetect=" + finalChanceToDetect + ", dice roll=" + roll + ", dice roll < finalChanceToDetect so returning detection SUCCESS");
|
|
}
|
|
else
|
|
{
|
|
sendConsoleMessage(objectToReceiveDetailedOutput, "passiveDetectInfo: getDetectChanceWithDetailedOutput() returned finalChanceToDetect=" + finalChanceToDetect + ", dice roll=" + roll + ", dice roll >= finalChanceToDetect so returning detection FAIL");
|
|
}
|
|
return (roll < finalChanceToDetect);
|
|
}
|
|
public static boolean testBubbleBreached(obj_id bubbleHolder, obj_id breacher, int volume) throws InterruptedException
|
|
{
|
|
if (hasObjVar(bubbleHolder, "debuggingPassiveDetectDetailedOutput"))
|
|
{
|
|
obj_id objectToReceiveDetailedOutput = bubbleHolder;
|
|
if (hasObjVar(bubbleHolder, "debuggingPassiveDetectDetailedOutputObject"))
|
|
{
|
|
String objVarValue = getStringObjVar(bubbleHolder, "debuggingPassiveDetectDetailedOutputObject");
|
|
if (objVarValue != null && objVarValue.length() > 0)
|
|
{
|
|
obj_id objVarValueAsOid = utils.stringToObjId(objVarValue.substring(1));
|
|
if (isValidId(objVarValueAsOid) && exists(objVarValueAsOid))
|
|
{
|
|
objectToReceiveDetailedOutput = objVarValueAsOid;
|
|
}
|
|
}
|
|
}
|
|
return passiveDetectHiddenTargetWithDetailedOutput(bubbleHolder, breacher, volume, objectToReceiveDetailedOutput);
|
|
}
|
|
else
|
|
{
|
|
return passiveDetectHiddenTarget(bubbleHolder, breacher, volume);
|
|
}
|
|
}
|
|
public static void testUseAction(obj_id player, obj_id object, int menuItem) throws InterruptedException
|
|
{
|
|
String invis = getInvisBuff(player);
|
|
if (invis != null && invis.length() > 0)
|
|
{
|
|
buff.removeBuff(player, invis);
|
|
}
|
|
}
|
|
public static void testInvisNonCombatAction(obj_id player, obj_id target) throws InterruptedException
|
|
{
|
|
testInvisCombatAction(player, target, -1);
|
|
}
|
|
public static void testInvisNonCombatAction(obj_id player, obj_id target, combat_data combatData) throws InterruptedException
|
|
{
|
|
if (!combatData.specialLine.equals("no_proc"))
|
|
{
|
|
testInvisCombatAction(player, target, combatData.minInvisLevelRequired);
|
|
}
|
|
}
|
|
public static void testInvisNonCombatAction(obj_id player, obj_id target, int minInvisRequiredForAction) throws InterruptedException
|
|
{
|
|
if (isIdValid(player) && exists(player) && beast_lib.isBeast(player))
|
|
{
|
|
player = getMaster(player);
|
|
}
|
|
String invis = getInvisBuff(player);
|
|
if (invis != null && !invis.startsWith("invis_"))
|
|
{
|
|
int pri = buff.getPriority(invis);
|
|
if (minInvisRequiredForAction == -1 || pri < minInvisRequiredForAction)
|
|
{
|
|
if (!buff.hasBuff(player, BUFF_NO_BREAK_INVIS))
|
|
{
|
|
buff.removeBuff(player, invis);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
public static void testInvisCombatAction(obj_id player, obj_id target) throws InterruptedException
|
|
{
|
|
testInvisCombatAction(player, target, -1);
|
|
}
|
|
public static void testInvisCombatAction(obj_id player, obj_id target, combat_data combatData) throws InterruptedException
|
|
{
|
|
if (!combatData.specialLine.equals("no_proc"))
|
|
{
|
|
testInvisCombatAction(player, target, combatData.minInvisLevelRequired);
|
|
}
|
|
}
|
|
public static void testInvisCombatAction(obj_id player, obj_id target, int minInvisRequiredForAction) throws InterruptedException
|
|
{
|
|
if (isIdValid(player) && exists(player) && beast_lib.isBeast(player))
|
|
{
|
|
player = getMaster(player);
|
|
}
|
|
String invis = getInvisBuff(player);
|
|
if (invis != null)
|
|
{
|
|
int pri = buff.getPriority(invis);
|
|
if (minInvisRequiredForAction == -1 || pri < minInvisRequiredForAction)
|
|
{
|
|
if (!buff.hasBuff(player, BUFF_NO_BREAK_INVIS))
|
|
{
|
|
combat.combatLog(player, target, "combatStandardAction", "Invisible - Clearing invisibility");
|
|
if (isPlayer(player))
|
|
{
|
|
utils.setScriptVar(player, "stealth.invisRemoved", invis);
|
|
utils.setScriptVar(player, "stealth.invisRemovedTime", getGameTime());
|
|
utils.setScriptVar(player, "stealth.invisRemovedTimeLeft", buff.getBuffTimeRemaining(player, invis));
|
|
}
|
|
buff.removeBuff(player, invis);
|
|
buff.applyBuff(player, "sp_attack_invis_recourse");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
public static void reinstateInvisFromCombat(obj_id player) throws InterruptedException
|
|
{
|
|
if (!isIdValid(player) || !exists(player) || !isPlayer(player))
|
|
{
|
|
return;
|
|
}
|
|
buff.removeBuff(player, "sp_attack_invis_recourse");
|
|
int invisTime = utils.getIntScriptVar(player, "stealth.invisRemovedTime");
|
|
String invisName = utils.getStringScriptVar(player, "stealth.invisRemoved");
|
|
float timeLeft = utils.getFloatScriptVar(player, "stealth.invisRemovedTimeLeft");
|
|
if (invisTime > 0 && invisName != null && invisName.length() > 0 && invisTime - getGameTime() < 2)
|
|
{
|
|
if (timeLeft > 0)
|
|
{
|
|
buff.applyBuff(player, invisName, timeLeft);
|
|
}
|
|
else
|
|
{
|
|
float duration = buff.getDuration(invisName);
|
|
if (duration < 0)
|
|
{
|
|
buff.applyBuff(player, invisName, -1);
|
|
}
|
|
else
|
|
{
|
|
clearPreviousInvis(player);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
public static void clearPreviousInvis(obj_id player) throws InterruptedException
|
|
{
|
|
if (!isPlayer(player))
|
|
{
|
|
return;
|
|
}
|
|
utils.removeScriptVar(player, "stealth.invisRemoved");
|
|
utils.removeScriptVar(player, "stealth.invisRemovedTime");
|
|
}
|
|
public static float calcBreachDistanceForSkill(obj_id player, String skillMod) throws InterruptedException
|
|
{
|
|
int mod = getEnhancedSkillStatisticModifier(player, skillMod);
|
|
float difference = INVIS_BREAK_MAX_FAR_DISTANCE - INVIS_BREAK_NEAR_DISTANCE;
|
|
return INVIS_BREAK_NEAR_DISTANCE + (difference / (1 + ((mod) / 100)));
|
|
}
|
|
public static void cleanupHate(obj_id player) throws InterruptedException
|
|
{
|
|
if (!isIdValid(player) || !exists(player))
|
|
{
|
|
return;
|
|
}
|
|
obj_id[] hateList = getHateList(player);
|
|
for (obj_id aHateList : hateList) {
|
|
if (isIdValid(aHateList) && exists(aHateList)) {
|
|
removeHateTarget(aHateList, player);
|
|
removeHateTarget(player, aHateList);
|
|
}
|
|
}
|
|
clearHateList(player);
|
|
}
|
|
public static obj_id makeBeastInvisible(obj_id player, String clientEffect) throws InterruptedException
|
|
{
|
|
if (!isIdValid(player) || !exists(player) || !beast_lib.isBeastMaster(player))
|
|
{
|
|
return null;
|
|
}
|
|
obj_id beast = beast_lib.getBeastOnPlayer(player);
|
|
if (!isIdValid(beast) || !exists(beast))
|
|
{
|
|
return null;
|
|
}
|
|
attachScript(beast, "systems.skills.stealth.stealth_monitor");
|
|
messageTo(beast, "updatePassiveRevealList", null, 10, false);
|
|
setState(beast, STATE_COVER, true);
|
|
setCreatureCoverVisibility(beast, false);
|
|
cleanupHate(beast);
|
|
stopCombat(beast);
|
|
utils.removeScriptVar(beast, "ai.combat.target");
|
|
addPassiveReveal(beast, player, 1);
|
|
makePassiveRevealed(beast);
|
|
if (clientEffect == null || clientEffect.length() <= 0)
|
|
{
|
|
clientEffect = "appearance/pt_smoke_puff.prt";
|
|
}
|
|
playClientEffectObj(beast, clientEffect, beast, "");
|
|
int covert_mastery = getEnhancedSkillStatisticModifierUncapped(player, "expertise_covert_mastery");
|
|
if (covert_mastery > 0)
|
|
{
|
|
buff.applyBuff(beast, "sp_covert_mastery");
|
|
}
|
|
return beast;
|
|
}
|
|
public static boolean canBeastStealth(obj_id beast) throws InterruptedException
|
|
{
|
|
obj_id master = getMaster(beast);
|
|
if (isDead(beast) || ai_lib.isInCombat(beast))
|
|
{
|
|
return false;
|
|
}
|
|
if (isIdValid(master) && exists(master) && getState(master, STATE_COVER) == 1)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
public static void makeCreatureVisible(obj_id creature) throws InterruptedException
|
|
{
|
|
if (!isIdValid(creature) || !exists(creature))
|
|
{
|
|
return;
|
|
}
|
|
detachScript(creature, "systems.skills.stealth.stealth_monitor");
|
|
setState(creature, STATE_COVER, false);
|
|
clearPassiveRevealList(creature);
|
|
setCreatureCoverVisibility(creature, true);
|
|
playClientEffectObj(creature, "appearance/pt_sonic_pulse.prt", creature, "");
|
|
}
|
|
public static void makeBeastVisible(obj_id player) throws InterruptedException
|
|
{
|
|
if (!isIdValid(player) || !exists(player) || !beast_lib.isBeastMaster(player))
|
|
{
|
|
return;
|
|
}
|
|
makeCreatureVisible(beast_lib.getBeastOnPlayer(player));
|
|
}
|
|
public static void makePassiveRevealed(obj_id target) throws InterruptedException
|
|
{
|
|
obj_id beast = null;
|
|
if (isIdValid(target) && exists(target) && beast_lib.isBeast(target))
|
|
{
|
|
obj_id master = getMaster(target);
|
|
if (isIdValid(master) && exists(master))
|
|
{
|
|
target = master;
|
|
}
|
|
}
|
|
if (isPlayer(target))
|
|
{
|
|
beast = beast_lib.getBeastOnPlayer(target);
|
|
}
|
|
if (group.isGrouped(target))
|
|
{
|
|
obj_id groupObj = getGroupObject(target);
|
|
obj_id[] groupMembers = getGroupMemberIds(groupObj);
|
|
int numGroupMembers = groupMembers.length;
|
|
for (obj_id groupie : groupMembers) {
|
|
if (isIdValid(groupie) && exists(groupie) && groupie != target) {
|
|
addPassiveReveal(target, groupie, 1);
|
|
if (isIdValid(beast) && exists(beast)) {
|
|
addPassiveReveal(beast, groupie, 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
public static void _makeInvisible(obj_id player, string_id flyText, String clientEffect, string_id msg, float breachDistance) throws InterruptedException
|
|
{
|
|
if (breachDistance <= INVIS_BREAK_NEAR_DISTANCE)
|
|
{
|
|
breachDistance = INVIS_BREAK_NEAR_DISTANCE + 1f;
|
|
}
|
|
attachScript(player, "systems.skills.stealth.stealth_monitor");
|
|
messageTo(player, "updatePassiveRevealList", null, 10, false);
|
|
setState(player, STATE_COVER, true);
|
|
setCreatureCoverVisibility(player, false);
|
|
cleanupHate(player);
|
|
makePassiveRevealed(player);
|
|
if (flyText != null)
|
|
{
|
|
showFlyTextPrivate(player, player, flyText, 1.5f, colors.TOMATO);
|
|
}
|
|
if (clientEffect != null && clientEffect.length() > 0)
|
|
{
|
|
playClientEffectObj(player, clientEffect, player, "");
|
|
}
|
|
if (msg != null)
|
|
{
|
|
sendSystemMessage(player, msg);
|
|
}
|
|
if (!utils.hasScriptVar(player, INVIS_UPKEEP_MSG_DISPATCHED))
|
|
{
|
|
messageTo(player, "invisibilityUpkeep", null, 1, false);
|
|
}
|
|
if (breachDistance > 0)
|
|
{
|
|
createTriggerVolume(INVIS_BREAK_RADIUS_FAR, breachDistance, true);
|
|
createTriggerVolume(INVIS_BREAK_RADIUS_NEAR, INVIS_BREAK_NEAR_DISTANCE, true);
|
|
}
|
|
}
|
|
public static void _makeVisible(obj_id player, string_id flyText, string_id msg) throws InterruptedException
|
|
{
|
|
removeTriggerVolume(INVIS_BREAK_RADIUS_FAR);
|
|
removeTriggerVolume(INVIS_BREAK_RADIUS_NEAR);
|
|
clearPassiveRevealList(player);
|
|
detachScript(player, "systems.skills.stealth.stealth_monitor");
|
|
if (!utils.hasScriptVar(player, "supressVisible"))
|
|
{
|
|
setState(player, STATE_COVER, false);
|
|
setCreatureCoverVisibility(player, true);
|
|
makeBeastVisible(player);
|
|
if (flyText != null)
|
|
{
|
|
showFlyTextPrivate(player, player, flyText, 1.5f, colors.TOMATO);
|
|
}
|
|
if (msg != null)
|
|
{
|
|
sendSystemMessage(player, msg);
|
|
}
|
|
playClientEffectObj(player, "appearance/pt_sonic_pulse.prt", player, "");
|
|
}
|
|
else
|
|
{
|
|
utils.removeScriptVar(player, "supressVisible");
|
|
}
|
|
}
|
|
public static boolean checkRevealRecourse(obj_id player) throws InterruptedException
|
|
{
|
|
return buff.hasBuff(player, "sp_sneak_recourse");
|
|
}
|
|
public static boolean checkAttackRevealRecourse(obj_id player) throws InterruptedException
|
|
{
|
|
return buff.hasBuff(player, "sp_attack_invis_recourse");
|
|
}
|
|
public static boolean canPerformForceCloak(obj_id player) throws InterruptedException
|
|
{
|
|
if (combat.isInCombat(player) && (int)getSkillStatisticModifier(player, "expertise_force_cloak_combat_escape") <= 0)
|
|
{
|
|
return false;
|
|
}
|
|
if (isDead(player) || isIncapacitated(player))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_do_it_state"));
|
|
return false;
|
|
}
|
|
if (buff.hasBuff(player, "battlefield_communication_run"))
|
|
{
|
|
return false;
|
|
}
|
|
if (checkRevealRecourse(player))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_do_it_recourse"));
|
|
return false;
|
|
}
|
|
if (utils.hasScriptVar(player, "petCreationPending") && utils.getIntScriptVar(player, "petCreationPending") > getGameTime())
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cannot_perform_calling_companion"));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
public static boolean canPerformHide(obj_id player) throws InterruptedException
|
|
{
|
|
return canPerformStationaryInvis(player);
|
|
}
|
|
public static void forceCloak(obj_id player) throws InterruptedException
|
|
{
|
|
if (buff.hasBuff(player, "fs_force_run"))
|
|
{
|
|
buff.removeBuff(player, "fs_force_run");
|
|
}
|
|
_makeInvisible(player, new string_id("combat_effects", "go_cloak"), "clienteffect/combat_special_attacker_cover.cef", null, -1);
|
|
}
|
|
public static void hide(obj_id player) throws InterruptedException
|
|
{
|
|
_makeInvisible(player, new string_id("spam", "hide_go"), "clienteffect/combat_special_attacker_cover.cef", null, -1);
|
|
}
|
|
public static boolean canPerformSmokeGrenade(obj_id player) throws InterruptedException
|
|
{
|
|
if (isDead(player) || isIncapacitated(player))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_do_it_state"));
|
|
return false;
|
|
}
|
|
if (!buff.canApplyBuff(player, "invis_sp_buff_invis_1"))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_apply_invis_buff"));
|
|
return false;
|
|
}
|
|
if (buff.hasBuff(player, "battlefield_communication_run"))
|
|
{
|
|
return false;
|
|
}
|
|
if (utils.hasScriptVar(player, "petCreationPending") && utils.getIntScriptVar(player, "petCreationPending") > getGameTime())
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cannot_perform_calling_companion"));
|
|
return false;
|
|
}
|
|
if (checkAttackRevealRecourse(player))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_do_it_attack_recourse"));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
public static boolean canPerformWithoutTrace(obj_id player) throws InterruptedException
|
|
{
|
|
if (isDead(player) || isIncapacitated(player))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_do_it_state"));
|
|
return false;
|
|
}
|
|
if (!buff.canApplyBuff(player, "invis_sp_buff_invis_notrace_1"))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_apply_invis_buff"));
|
|
return false;
|
|
}
|
|
if (buff.hasBuff(player, "battlefield_communication_run"))
|
|
{
|
|
return false;
|
|
}
|
|
if (utils.hasScriptVar(player, "petCreationPending") && utils.getIntScriptVar(player, "petCreationPending") > getGameTime())
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cannot_perform_calling_companion"));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
public static boolean canPerformStationaryInvis(obj_id player) throws InterruptedException
|
|
{
|
|
if (isDead(player) || isIncapacitated(player))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_do_it_state"));
|
|
return false;
|
|
}
|
|
if (!buff.canApplyBuff(player, "invis_blendIn"))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_apply_invis_buff"));
|
|
return false;
|
|
}
|
|
if (buff.hasBuff(player, "battlefield_communication_run"))
|
|
{
|
|
return false;
|
|
}
|
|
if (utils.hasScriptVar(player, "petCreationPending") && utils.getIntScriptVar(player, "petCreationPending") > getGameTime())
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cannot_perform_calling_companion"));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
public static void smokeGrenade(obj_id player) throws InterruptedException
|
|
{
|
|
_makeInvisible(player, new string_id("spam", "smokegrenade"), "appearance/pt_smoke_puff.prt", null, -1);
|
|
buff.applyBuff(player, BUFF_NO_BREAK_INVIS);
|
|
}
|
|
public static void bothanInnate(obj_id player) throws InterruptedException
|
|
{
|
|
_makeInvisible(player, new string_id("spam", "fly_bothan_ability_1"), "appearance/pt_smoke_puff.prt", null, -1);
|
|
}
|
|
public static boolean canPerformStealth(obj_id player) throws InterruptedException
|
|
{
|
|
if (isDead(player) || isIncapacitated(player))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_do_it_state"));
|
|
return false;
|
|
}
|
|
if (ai_lib.isInCombat(player))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_do_it_combat"));
|
|
return false;
|
|
}
|
|
String invis = getInvisBuff(player);
|
|
if (invis != null)
|
|
{
|
|
if (invis.startsWith("invis_sp_buff_invis_notrace"))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_apply_invis_buff"));
|
|
return false;
|
|
}
|
|
}
|
|
if (buff.hasBuff(player, "battlefield_communication_run"))
|
|
{
|
|
return false;
|
|
}
|
|
if (!hasServerCoverState(player))
|
|
{
|
|
if (checkRevealRecourse(player))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_do_it_recourse"));
|
|
return false;
|
|
}
|
|
}
|
|
if (utils.hasScriptVar(player, "petCreationPending") && utils.getIntScriptVar(player, "petCreationPending") > getGameTime())
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cannot_perform_calling_companion"));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
public static void stealth(obj_id player) throws InterruptedException
|
|
{
|
|
_makeInvisible(player, new string_id("spam", "stealth"), "appearance/pt_smoke_puff.prt", null, calcBreachDistanceForSkill(player, "camouflage"));
|
|
buff.applyBuff(player, BUFF_NO_BREAK_INVIS);
|
|
}
|
|
public static void withoutTrace(obj_id player) throws InterruptedException
|
|
{
|
|
_makeInvisible(player, new string_id("spam", "without_trace"), "appearance/pt_smoke_puff.prt", null, -1);
|
|
int covert_mastery = getEnhancedSkillStatisticModifierUncapped(player, "expertise_covert_mastery");
|
|
if (covert_mastery > 0)
|
|
{
|
|
buff.applyBuff(player, "sp_covert_mastery");
|
|
}
|
|
buff.applyBuff(player, BUFF_NO_BREAK_INVIS);
|
|
}
|
|
public static void decoyStealth(obj_id player) throws InterruptedException
|
|
{
|
|
_makeInvisible(player, new string_id("spam", "decoy_stealth"), "", null, -1);
|
|
buff.applyBuff(player, BUFF_NO_BREAK_INVIS);
|
|
}
|
|
public static void invisBuffAdded(obj_id mobile, String effectName) throws InterruptedException
|
|
{
|
|
effectName = toLower(effectName);
|
|
messageTo(mobile, "addAppearanceItemEffect", null, 1, false);
|
|
if (effectName.startsWith("invis_sp_buff_invis_notrace"))
|
|
{
|
|
withoutTrace(mobile);
|
|
}
|
|
else if (effectName.startsWith("invis_sp_buff_invis"))
|
|
{
|
|
smokeGrenade(mobile);
|
|
}
|
|
else if (effectName.startsWith("invis_bothan_ability_1"))
|
|
{
|
|
bothanInnate(mobile);
|
|
}
|
|
else if (effectName.startsWith("invis_sp_buff_stealth"))
|
|
{
|
|
stealth(mobile);
|
|
}
|
|
else if (effectName.startsWith("invis_fs_buff_invis"))
|
|
{
|
|
forceCloak(mobile);
|
|
}
|
|
else if (effectName.startsWith("invis_sm_buff_invis"))
|
|
{
|
|
stealth(mobile);
|
|
}
|
|
else if (effectName.startsWith("invis_sp_diversion_stealth"))
|
|
{
|
|
decoyStealth(mobile);
|
|
}
|
|
}
|
|
public static boolean canPerformCamouflageSelf(obj_id player) throws InterruptedException
|
|
{
|
|
if (isDead(player) || isIncapacitated(player))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_do_it_state"));
|
|
return false;
|
|
}
|
|
if (checkRevealRecourse(player))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_do_it_recourse"));
|
|
return false;
|
|
}
|
|
if (!buff.canApplyBuff(player, "invis_camouflage"))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_apply_invis_buff"));
|
|
return false;
|
|
}
|
|
if (buff.hasBuff(player, "battlefield_communication_run"))
|
|
{
|
|
return false;
|
|
}
|
|
if (isInUrban(player))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_camo_self_urban"));
|
|
return false;
|
|
}
|
|
obj_id kit = getCamoKitForCurrentPlanet(player);
|
|
if (!isIdValid(kit))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_camo_self_no_kit"));
|
|
return false;
|
|
}
|
|
utils.setScriptVar(player, CAMO_KIT_ID, kit);
|
|
return true;
|
|
}
|
|
public static void camouflageSelf(obj_id player) throws InterruptedException
|
|
{
|
|
obj_id kit = utils.getObjIdScriptVar(player, CAMO_KIT_ID);
|
|
if (!isIdValid(kit))
|
|
{
|
|
return;
|
|
}
|
|
consumeCamoKit(kit);
|
|
boolean success = witnessModifiedSkillCheck(player, "camouflage", 15, 5, 0);
|
|
if (success)
|
|
{
|
|
_makeInvisible(player, new string_id("spam", "camouflaged"), "appearance/pt_smoke_puff.prt", null, calcBreachDistanceForSkill(player, "camouflage"));
|
|
}
|
|
else
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "failedcamo"));
|
|
}
|
|
}
|
|
public static boolean canPerformCamouflageAlly(obj_id player, obj_id target) throws InterruptedException
|
|
{
|
|
if (!isIdValid(target))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "no_target"));
|
|
return false;
|
|
}
|
|
if (!isPlayer(target))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "bad_target"));
|
|
return false;
|
|
}
|
|
int shapechange = buff.getBuffOnTargetFromGroup(target, "shapechange");
|
|
if (shapechange != 0)
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "not_while_shapechanged"));
|
|
return false;
|
|
}
|
|
if (target == player)
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_apply_invis_self"));
|
|
return false;
|
|
}
|
|
if (buff.hasBuff(target, "battlefield_communication_run"))
|
|
{
|
|
return false;
|
|
}
|
|
if (isDead(player) || isIncapacitated(player))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_do_it_state"));
|
|
return false;
|
|
}
|
|
if (getDistance(player, target) > 46)
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_camo_ally_far"));
|
|
return false;
|
|
}
|
|
if (!pvpCanHelp(player, target))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_camo_ally_faction"));
|
|
return false;
|
|
}
|
|
if (checkRevealRecourse(target))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_do_it_recourse_other"));
|
|
return false;
|
|
}
|
|
int tGuildId = getGuildId(target);
|
|
int sGuildId = getGuildId(player);
|
|
boolean isInSameGuild = (tGuildId != 0) && (tGuildId == sGuildId);
|
|
if (!isInSameGuild && !group.inSameGroup(player, target))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_camo_ally_not_allied"));
|
|
return false;
|
|
}
|
|
if (pvpIsDueling(player, target))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_camo_ally_dueling"));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
public static boolean canPerformUrbanStealth(obj_id player, obj_id possibleHep) throws InterruptedException
|
|
{
|
|
if (buff.hasBuff(player, "forceRun") || buff.hasBuff(player, "forceRun_1") || buff.hasBuff(player, "forceRun_2"))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_fc_run"));
|
|
return false;
|
|
}
|
|
if (buff.hasBuff(player, "battlefield_communication_run"))
|
|
{
|
|
return false;
|
|
}
|
|
if (isDead(player) || isIncapacitated(player))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_do_it_state"));
|
|
return false;
|
|
}
|
|
if (checkRevealRecourse(player))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_do_it_recourse"));
|
|
return false;
|
|
}
|
|
if (!buff.canApplyBuff(player, "invis_urbanStealth"))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_apply_invis_buff"));
|
|
return false;
|
|
}
|
|
if (!stealth.isInUrban(player))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_urban_stealth_environment"));
|
|
return false;
|
|
}
|
|
obj_id hep = stealth.getHEPObj(player, possibleHep);
|
|
if (!isIdValid(hep))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_urban_stealth_no_hep"));
|
|
return false;
|
|
}
|
|
if (!buff.hasBuff(player, "invis_blendIn"))
|
|
{
|
|
int sGuildId = getGuildId(player);
|
|
boolean isInSameGuild = false;
|
|
obj_id[] stuff = getCreaturesInRange(player, 20f);
|
|
for (obj_id aStuff : stuff) {
|
|
if (isPlayer(aStuff) || ai_lib.isNpc(aStuff)) {
|
|
isInSameGuild = (sGuildId != 0) && (getGuildId(aStuff) == sGuildId);
|
|
if (!isInSameGuild && !group.inSameGroup(player, aStuff)) {
|
|
sendSystemMessage(player, new string_id("spam", "cant_urban_stealth_people_in_area"));
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
utils.setScriptVar(player, CAMO_KIT_ID, hep);
|
|
return true;
|
|
}
|
|
public static void urbanStealth(obj_id player) throws InterruptedException
|
|
{
|
|
obj_id hep = utils.getObjIdScriptVar(player, CAMO_KIT_ID);
|
|
if (!isIdValid(hep))
|
|
{
|
|
return;
|
|
}
|
|
if (!testAndDoHepUpkeep(hep, player, false))
|
|
{
|
|
return;
|
|
}
|
|
utils.makeItemNoDrop(hep);
|
|
setObjVar(player, ACTIVE_HEP, hep);
|
|
if (hasInvisibleBuff(player))
|
|
{
|
|
utils.setScriptVar(player, "supressVisible", 1);
|
|
}
|
|
_makeInvisible(player, new string_id("spam", "stealthon"), "appearance/pt_detector.prt", null, calcBreachDistanceForSkill(player, "stealth"));
|
|
}
|
|
public static boolean canPerformWildernessStealth(obj_id player) throws InterruptedException
|
|
{
|
|
if (buff.hasBuff(player, "forceRun") || buff.hasBuff(player, "forceRun_1") || buff.hasBuff(player, "forceRun_2"))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_fc_run"));
|
|
return false;
|
|
}
|
|
if (buff.hasBuff(player, "battlefield_communication_run"))
|
|
{
|
|
return false;
|
|
}
|
|
if (isDead(player) || isIncapacitated(player))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_do_it_state"));
|
|
return false;
|
|
}
|
|
if (checkRevealRecourse(player))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_do_it_recourse"));
|
|
return false;
|
|
}
|
|
if (!buff.canApplyBuff(player, "invis_wildernessStealth"))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_apply_invis_buff"));
|
|
return false;
|
|
}
|
|
if (!stealth.isInWilderness(player))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_wilderness_stealth_environment"));
|
|
return false;
|
|
}
|
|
boolean isHidden = hasInvisibleBuff(player);
|
|
if (!isHidden)
|
|
{
|
|
obj_id kit = getCamoKitForCurrentPlanet(player);
|
|
if (!isIdValid(kit))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_wilderness_stealth_no_kit"));
|
|
return false;
|
|
}
|
|
utils.setScriptVar(player, CAMO_KIT_ID, kit);
|
|
}
|
|
return true;
|
|
}
|
|
public static void wildernessStealth(obj_id player) throws InterruptedException
|
|
{
|
|
obj_id kit = utils.getObjIdScriptVar(player, CAMO_KIT_ID);
|
|
int penalty = 0;
|
|
if (!hasInvisibleBuff(player))
|
|
{
|
|
if (!isIdValid(kit))
|
|
{
|
|
return;
|
|
}
|
|
consumeCamoKit(kit);
|
|
penalty = 50;
|
|
}
|
|
else
|
|
{
|
|
utils.setScriptVar(player, "supressVisible", 1);
|
|
}
|
|
boolean success = witnessModifiedSkillCheck(player, "stealth", 20, 10, penalty);
|
|
if (success)
|
|
{
|
|
_makeInvisible(player, new string_id("spam", "stealthon"), "appearance/pt_smoke_puff.prt", null, calcBreachDistanceForSkill(player, "stealth"));
|
|
}
|
|
else
|
|
{
|
|
utils.removeScriptVar(player, "supressVisible");
|
|
sendSystemMessage(player, new string_id("spam", "stealthfail"));
|
|
}
|
|
}
|
|
public static boolean canPerformCover(obj_id player) throws InterruptedException
|
|
{
|
|
if (isDead(player) || isIncapacitated(player))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_do_it_state"));
|
|
return false;
|
|
}
|
|
if (buff.hasBuff(player, "battlefield_communication_run"))
|
|
{
|
|
return false;
|
|
}
|
|
if (checkRevealRecourse(player))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_do_it_recourse"));
|
|
return false;
|
|
}
|
|
if (!buff.canApplyBuff(player, "invis_cover"))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_apply_invis_buff"));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
public static void cover(obj_id player) throws InterruptedException
|
|
{
|
|
_makeInvisible(player, new string_id("combat_effects", "go_cover"), "clienteffect/combat_special_attacker_cover.cef", null, calcBreachDistanceForSkill(player, "camouflage"));
|
|
sendSystemMessage(player, new string_id("cbt_spam", "cover_success_single"));
|
|
}
|
|
public static void disableHep(obj_id hep, obj_id player) throws InterruptedException
|
|
{
|
|
if (isIdValid(hep) && exists(hep))
|
|
{
|
|
int power = getCount(hep);
|
|
float multiplier = .5f;
|
|
if (power > HEP_UPKEEP_COST)
|
|
{
|
|
multiplier = .95f;
|
|
}
|
|
power = (int)(getIntObjVar(hep, HEP_BASE_POWER) * multiplier);
|
|
setCount(hep, power);
|
|
setObjVar(hep, HEP_BASE_POWER, power);
|
|
utils.clearNoDropFromItem(hep);
|
|
if (power < HEP_UPKEEP_COST)
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "hep_low_power"));
|
|
setCondition(hep, CONDITION_DISABLED);
|
|
}
|
|
}
|
|
if (isIdValid(player))
|
|
{
|
|
removeObjVar(player, ACTIVE_HEP);
|
|
}
|
|
}
|
|
public static boolean testAndDoHepUpkeep(obj_id hep, obj_id player, boolean silent) throws InterruptedException
|
|
{
|
|
int power = getCount(hep);
|
|
if (power < HEP_UPKEEP_COST)
|
|
{
|
|
if (!silent)
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "hep_out_of_juice"));
|
|
}
|
|
return false;
|
|
}
|
|
power = getCount(hep) - HEP_UPKEEP_COST;
|
|
setCount(hep, power);
|
|
return true;
|
|
}
|
|
public static boolean checkSpyStealthUpkeep(obj_id player) throws InterruptedException
|
|
{
|
|
float camouflage = getEnhancedSkillStatisticModifierUncapped(player, "camouflage");
|
|
camouflage += getEnhancedSkillStatisticModifierUncapped(player, "stealth");
|
|
float drainRatio = 10.0f;
|
|
if (camouflage < 100.0f)
|
|
{
|
|
drainRatio = 7.91f - (.1f / (.1f + ((camouflage) / 100.0f)));
|
|
}
|
|
int actionCost = (int)(getMaxAction(player) / drainRatio);
|
|
int action = testDrainAttribute(player, ACTION, actionCost);
|
|
if (action < 0 || !drainAttributes(player, actionCost, 0))
|
|
{
|
|
checkForAndMakeVisible(player);
|
|
return false;
|
|
}
|
|
string_id strSpam = new string_id("combat_effects", "damage_fly");
|
|
prose_package pp = new prose_package();
|
|
pp = prose.setStringId(pp, strSpam);
|
|
pp = prose.setDI(pp, -actionCost);
|
|
showFlyText(player, pp, 1f, colors.GREEN);
|
|
return true;
|
|
}
|
|
public static boolean checkUrbanStealthUpkeep(obj_id player) throws InterruptedException
|
|
{
|
|
if (!isInUrban(player))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_urban_stealth_environment"));
|
|
buff.removeBuff(player, "invis_urbanStealth");
|
|
return false;
|
|
}
|
|
obj_id hep = getObjIdObjVar(player, ACTIVE_HEP);
|
|
if (!isIdValid(hep) || !exists(hep))
|
|
{
|
|
buff.removeBuff(player, "invis_urbanStealth");
|
|
return false;
|
|
}
|
|
if (!testAndDoHepUpkeep(hep, player, false))
|
|
{
|
|
buff.removeBuff(player, "invis_urbanStealth");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
public static boolean checkWildernessStealthUpkeep(obj_id player) throws InterruptedException
|
|
{
|
|
if (!isInWilderness(player))
|
|
{
|
|
sendSystemMessage(player, new string_id("spam", "cant_wilderness_stealth_environment"));
|
|
buff.removeBuff(player, "invis_wildernessStealth");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
public static boolean checkForceCloakUpkeep(obj_id player) throws InterruptedException
|
|
{
|
|
float forceCost = dataTableGetFloat(jedi.JEDI_ACTIONS_FILE, "forceCloak", "extraForceCost");
|
|
obj_id[] players = getPlayerCreaturesInRange(player, stealth.INVIS_BREAK_MAX_FAR_DISTANCE);
|
|
obj_id[] npcs = getNPCsInRange(player, stealth.INVIS_BREAK_MAX_FAR_DISTANCE);
|
|
int nearCount = players.length + npcs.length;
|
|
int i = 0;
|
|
for (i = 0; i < players.length; i++)
|
|
{
|
|
if (group.inSameGroup(player, players[i]))
|
|
{
|
|
nearCount--;
|
|
}
|
|
}
|
|
for (i = 0; i < npcs.length; i++)
|
|
{
|
|
if (group.inSameGroup(player, npcs[i]))
|
|
{
|
|
nearCount--;
|
|
}
|
|
}
|
|
if (nearCount < 0)
|
|
{
|
|
nearCount = 0;
|
|
}
|
|
forceCost *= nearCount;
|
|
if (!jedi.drainForcePower(player, (int)forceCost))
|
|
{
|
|
buff.removeBuff(player, "invi_forceCloak");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
public static boolean checkForAndMakeVisible(obj_id player) throws InterruptedException
|
|
{
|
|
String ibuff = getInvisBuff(player);
|
|
if (ibuff == null || ibuff.length() < 1)
|
|
{
|
|
return false;
|
|
}
|
|
buff.applyBuff(player, "sp_sneak_recourse");
|
|
buff.removeBuff(player, ibuff);
|
|
return true;
|
|
}
|
|
public static boolean checkForAndMakeVisibleNoRecourse(obj_id player) throws InterruptedException
|
|
{
|
|
String ibuff = getInvisBuff(player);
|
|
if (ibuff == null || ibuff.length() < 1)
|
|
{
|
|
return false;
|
|
}
|
|
buff.removeBuff(player, ibuff);
|
|
return true;
|
|
}
|
|
public static boolean hasInvisibleBuff(obj_id object) throws InterruptedException
|
|
{
|
|
return getInvisBuff(object) != null || (isMob(object) && !getCreatureCoverVisibility(object));
|
|
}
|
|
public static String getInvisBuff(obj_id player) throws InterruptedException
|
|
{
|
|
int[] buffs = buff.getAllBuffs(player);
|
|
if (buffs == null)
|
|
{
|
|
return null;
|
|
}
|
|
String curBuff = "";
|
|
for (int aBuff : buffs) {
|
|
curBuff = buff.getBuffNameFromCrc(aBuff);
|
|
if (curBuff != null && curBuff.startsWith("invis_")) {
|
|
return curBuff;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
public static boolean hasServerCoverState(obj_id player) throws InterruptedException
|
|
{
|
|
return getState(player, STATE_COVER) > 0;
|
|
}
|
|
public static obj_id getHEPObj(obj_id player, obj_id possibleHep) throws InterruptedException
|
|
{
|
|
int power = 0;
|
|
if (hasObjVar(possibleHep, "isHEP"))
|
|
{
|
|
power = getCount(possibleHep);
|
|
if (power >= HEP_UPKEEP_COST)
|
|
{
|
|
return possibleHep;
|
|
}
|
|
}
|
|
obj_id pInv = utils.getInventoryContainer(player);
|
|
if (!isIdValid(pInv))
|
|
{
|
|
return null;
|
|
}
|
|
obj_id[] contents = getContents(pInv);
|
|
obj_id hep = null;
|
|
for (obj_id content : contents) {
|
|
if (hasObjVar(content, "isHEP")) {
|
|
power = getCount(content);
|
|
if (power >= HEP_UPKEEP_COST) {
|
|
hep = content;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return hep;
|
|
}
|
|
public static obj_id getCamoKitForCurrentPlanet(obj_id player) throws InterruptedException
|
|
{
|
|
String planetName = getCurrentSceneName();
|
|
if (planetName.length() > 7)
|
|
{
|
|
String sceneSubString = planetName.substring(0, 8);
|
|
if (sceneSubString.equals("kashyyyk"))
|
|
{
|
|
planetName = "kashyyyk";
|
|
}
|
|
}
|
|
obj_id pInv = utils.getInventoryContainer(player);
|
|
if (!isIdValid(pInv))
|
|
{
|
|
return null;
|
|
}
|
|
obj_id[] contents = getContents(pInv);
|
|
obj_id kit = null;
|
|
for (obj_id content : contents) {
|
|
if (hasObjVar(content, "camokit")) {
|
|
String kitPlanet = getStringObjVar(content, "camokit");
|
|
if (kitPlanet.equals(planetName)) {
|
|
kit = content;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return kit;
|
|
}
|
|
public static void consumeCamoKit(obj_id kit) throws InterruptedException
|
|
{
|
|
int count = getCount(kit);
|
|
if (count <= 1)
|
|
{
|
|
destroyObject(kit);
|
|
}
|
|
else
|
|
{
|
|
count--;
|
|
setCount(kit, count);
|
|
}
|
|
}
|
|
public static boolean isInWilderness(obj_id player) throws InterruptedException
|
|
{
|
|
obj_id container = getTopMostContainer(player);
|
|
if (isIdValid(container) && isGameObjectTypeOf(container, GOT_building))
|
|
{
|
|
return true;
|
|
}
|
|
location loc = getLocation(player);
|
|
if (locations.isInCity(loc) || city.isInCity(loc))
|
|
{
|
|
return false;
|
|
}
|
|
obj_id[] stuff = getNonCreaturesInRange(loc, 50f);
|
|
int numStructures = 0;
|
|
for (obj_id aStuff : stuff) {
|
|
if (isGameObjectTypeOf(aStuff, GOT_building) || isGameObjectTypeOf(aStuff, GOT_installation)) {
|
|
numStructures++;
|
|
}
|
|
}
|
|
if (numStructures > MAX_BUILDINGS_FOR_WILDNERNESS)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
public static boolean isInUrban(obj_id player) throws InterruptedException
|
|
{
|
|
return (!isInWilderness(player));
|
|
}
|
|
public static boolean isFlagSet(int mask, int flag) throws InterruptedException
|
|
{
|
|
return (mask & flag) == flag;
|
|
}
|
|
public static boolean isPvPTrap(obj_id trap) throws InterruptedException
|
|
{
|
|
return getIntObjVar(trap, TRIGGER_TYPE) == TRIGGER_TYPE_PROXIMITY;
|
|
}
|
|
public static obj_id createDecoy(obj_id spy) throws InterruptedException
|
|
{
|
|
location myLoc = getLocation(spy);
|
|
int species = getSpecies(spy);
|
|
int gender = getGender(spy);
|
|
String template = "object/mobile/hologram/";
|
|
String speciesString = "human";
|
|
String genderString = "male";
|
|
switch (species)
|
|
{
|
|
case SPECIES_RODIAN:
|
|
speciesString = "rodian";
|
|
break;
|
|
case SPECIES_TRANDOSHAN:
|
|
speciesString = "trandoshan";
|
|
break;
|
|
case SPECIES_MON_CALAMARI:
|
|
speciesString = "moncal";
|
|
break;
|
|
case SPECIES_WOOKIEE:
|
|
speciesString = "wookiee";
|
|
break;
|
|
case SPECIES_BOTHAN:
|
|
speciesString = "bothan";
|
|
break;
|
|
case SPECIES_TWILEK:
|
|
speciesString = "twilek";
|
|
break;
|
|
case SPECIES_ZABRAK:
|
|
speciesString = "zabrak";
|
|
break;
|
|
case SPECIES_ITHORIAN:
|
|
speciesString = "ithorian";
|
|
break;
|
|
case SPECIES_SULLUSTAN:
|
|
speciesString = "sullustan";
|
|
break;
|
|
}
|
|
if (gender == GENDER_FEMALE)
|
|
{
|
|
genderString = "female";
|
|
}
|
|
template += speciesString + "_" + genderString + ".iff";
|
|
obj_id hologram = createObject(template, myLoc);
|
|
if (isIdValid(hologram))
|
|
{
|
|
setMaster(hologram, spy);
|
|
setScale(hologram, getScale(spy));
|
|
setYaw(hologram, getYaw(spy));
|
|
setName(hologram, getName(spy));
|
|
setDescriptionStringId(hologram, new string_id("mob/creature_names", "decoy_bio"));
|
|
setInvulnerable(hologram, false);
|
|
factions.setFaction(hologram, factions.getFaction(spy));
|
|
setDecoyOrigin(hologram, spy);
|
|
custom_var[] var_list = getAllCustomVars(spy);
|
|
if (var_list != null && var_list.length > 0)
|
|
{
|
|
ranged_int_custom_var ricv;
|
|
String var;
|
|
for (custom_var aVar_list : var_list) {
|
|
ricv = (ranged_int_custom_var) aVar_list;
|
|
var = ricv.getVarName();
|
|
int value = ricv.getValue();
|
|
if (value != 0) {
|
|
setRangedIntCustomVarValue(hologram, var, value);
|
|
}
|
|
}
|
|
}
|
|
obj_id[] contents = getAllWornItems(spy, false);
|
|
obj_id headSlotItem = getObjectInSlot(spy, "hat");
|
|
utils.setObjVar(hologram, "hologram_performer", 1);
|
|
if (contents != null && contents.length > 0)
|
|
{
|
|
custom_var[] object_var;
|
|
obj_id newObject;
|
|
ranged_int_custom_var ricv;
|
|
String var;
|
|
|
|
for (obj_id content : contents) {
|
|
if (isIdValid(content)) {
|
|
if (getContainerType(content) == 0) {
|
|
if (!(getTemplateName(content)).endsWith("player.iff")) {
|
|
if (headSlotItem == content && isPlayerHelmetHidden(spy)) {
|
|
continue;
|
|
}
|
|
if (getGameObjectType(content) == GOT_misc_appearance_only_invisible) {
|
|
continue;
|
|
}
|
|
object_var = getAllCustomVars(content);
|
|
newObject = createObject(getTemplateName(content), hologram, "");
|
|
if (object_var != null && isIdValid(newObject)) {
|
|
for (custom_var anObject_var : object_var) {
|
|
ricv = (ranged_int_custom_var) anObject_var;
|
|
var = ricv.getVarName();
|
|
int value = ricv.getValue();
|
|
if (value != 0) {
|
|
setRangedIntCustomVarValue(newObject, var, value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
obj_id backpack = getObjectInSlot(spy, "back");
|
|
if (isIdValid(backpack) && exists(backpack) && !isPlayerBackpackHidden(spy))
|
|
{
|
|
custom_var[] object_var = getAllCustomVars(backpack);
|
|
obj_id newObject = createObject(getTemplateName(backpack), hologram, "back");
|
|
if (object_var != null && isIdValid(newObject))
|
|
{
|
|
ranged_int_custom_var ricv;
|
|
String var;
|
|
for (custom_var anObject_var : object_var) {
|
|
ricv = (ranged_int_custom_var) anObject_var;
|
|
var = ricv.getVarName();
|
|
int value = ricv.getValue();
|
|
if (value != 0) {
|
|
setRangedIntCustomVarValue(newObject, var, value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
obj_id spyWeapon = getCurrentWeapon(spy);
|
|
obj_id holoWeapon;
|
|
if (isDefaultWeapon(spyWeapon))
|
|
{
|
|
holoWeapon = getCurrentWeapon(hologram);
|
|
}
|
|
else
|
|
{
|
|
holoWeapon = createObject(getTemplateName(spyWeapon), hologram, "");
|
|
}
|
|
setObjVar(hologram, "intCombatDifficulty", getLevel(spy));
|
|
setLevel(hologram, getLevel(spy));
|
|
setObjVar(hologram, "difficultyClass", 0);
|
|
if (isIdValid(holoWeapon))
|
|
{
|
|
setWeaponAttackSpeed(holoWeapon, 1.0f);
|
|
setWeaponMaxDamage(holoWeapon, 2);
|
|
setWeaponMinDamage(holoWeapon, 1);
|
|
weapons.setWeaponData(holoWeapon);
|
|
utils.setScriptVar(holoWeapon, "isCreatureWeapon", 1);
|
|
}
|
|
setCurrentWeapon(hologram, holoWeapon);
|
|
setMaxAttrib(hologram, HEALTH, getMaxAttrib(spy, HEALTH));
|
|
setAttrib(hologram, HEALTH, getMaxAttrib(spy, HEALTH));
|
|
utils.setScriptVar(spy, combat.DAMAGE_REDIRECT, hologram);
|
|
attachScript(hologram, "ai.ai");
|
|
attachScript(hologram, "ai.creature_combat");
|
|
attachScript(hologram, "systems.combat.combat_actions");
|
|
attachScript(hologram, "ai.spy_decoy");
|
|
int armorRating = utils.getIntScriptVar(spy, "armor.cache.generalProtection");
|
|
utils.setScriptVar(hologram, "armor.cache.generalProtection", armorRating);
|
|
int[] buffCrc = buff.getAllBuffs(spy);
|
|
if (buffCrc != null && buffCrc.length > 0)
|
|
{
|
|
String curBuff;
|
|
for (int aBuffCrc : buffCrc) {
|
|
curBuff = buff.getBuffNameFromCrc(aBuffCrc);
|
|
if (curBuff != null && curBuff.startsWith("invis_")) {
|
|
continue;
|
|
}
|
|
buff.applyBuff(hologram, aBuffCrc, 360.0f);
|
|
}
|
|
}
|
|
float dodgeChance = combat.getDefenderDodgeChance(spy);
|
|
float parryChance = combat.getDefenderParryChance(spy);
|
|
float blockChance = combat.getDefenderBlockChance(spy);
|
|
float glanceChance = combat.getDefenderGlancingBlowChance(spy);
|
|
float evadeChance = combat.getDefenderEvasionChance(spy);
|
|
addSkillModModifier(hologram, "expertise_dodge", "expertise_dodge", (int)dodgeChance, 20.0f, false, true);
|
|
addSkillModModifier(hologram, "expertise_parry", "expertise_parry", (int)parryChance, 20.0f, false, true);
|
|
addSkillModModifier(hologram, "expertise_block_chance", "expertise_block_chance", (int)blockChance, 20.0f, false, true);
|
|
addSkillModModifier(hologram, "expertise_glancing_blow_all", "expertise_glancing_blow_all", (int)glanceChance, 20.0f, false, true);
|
|
addSkillModModifier(hologram, "expertise_evasion_chance", "expertise_evasion_chance", (int)evadeChance, 20.0f, false, true);
|
|
if (hasCommand(spy, "sp_avoid_damage"))
|
|
{
|
|
messageTo(hologram, "queue_ad", null, 1.0f, false);
|
|
}
|
|
int diversionLevel = getEnhancedSkillStatisticModifierUncapped(spy, "expertise_improved_decoy");
|
|
if (diversionLevel > 0)
|
|
{
|
|
utils.setScriptVar(hologram, "flank", true);
|
|
}
|
|
else
|
|
{
|
|
utils.setScriptVar(hologram, "flank", false);
|
|
}
|
|
return hologram;
|
|
}
|
|
return null;
|
|
}
|
|
public static boolean isDecoy(obj_id object) throws InterruptedException
|
|
{
|
|
return utils.hasScript(object, "ai.spy_decoy");
|
|
}
|
|
}
|