Files
src-1.2/engine/server/library/serverScript/src/shared/ScriptMethodsCombat.cpp
T

2467 lines
89 KiB
C++
Executable File

//========================================================================
//
// ScriptMethodsCombat.cpp - implements script methods dealing with general
// object info.
//
// copyright 2001 Sony Online Entertainment
//
//========================================================================
#include "serverScript/FirstServerScript.h"
#include "serverScript/JavaLibrary.h"
#include "serverGame/AiLogManager.h"
#include "serverGame/ConfigServerGame.h"
#include "serverGame/ContainerInterface.h"
#include "serverGame/CreatureController.h"
#include "serverGame/CreatureObject.h"
#include "serverGame/PlayerCreatureController.h"
#include "serverGame/PlayerObject.h"
#include "serverGame/ServerWorld.h"
#include "serverGame/WeaponObject.h"
#include "serverScript/GameScriptObject.h"
#include "serverScript/ScriptParameters.h"
#include "serverUtility/ServerClock.h"
#include "sharedGame/CommandTable.h"
#include "sharedGame/ClientCombatManagerSupport.h"
#include "sharedFoundation/ConstCharCrcLowerString.h"
#include "sharedFoundation/GameControllerMessage.h"
#include "sharedFoundation/TemporaryCrcString.h"
#include "sharedLog/Log.h"
#include "sharedNetworkMessages/MessageQueueCombatSpam.h"
#include "sharedObject/CellProperty.h"
#include "sharedObject/NetworkIdManager.h"
#include "sharedObject/ObjectTemplateList.h"
#include "SwgGameServer/CombatEngine.h"
#include "SwgGameServer/ConfigCombatEngine.h"
#include "swgSharedUtility/CombatEngineData.h"
#include "swgSharedNetworkMessages/MessageQueueCombatAction.h"
#include "UnicodeUtils.h"
using namespace JNIWrappersNamespace;
static const std::string UNSKILLED_COMMAND("unskilled");
// ======================================================================
// ScriptMethodsCombatNamespace
// ======================================================================
namespace ScriptMethodsCombatNamespace
{
bool install();
jint JNICALL getCombatDuration(JNIEnv * env, jobject self, jlong object);
jlong JNICALL getCurrentWeapon(JNIEnv *env, jobject self, jlong target);
jboolean JNICALL setCurrentWeapon(JNIEnv *env, jobject self, jlong target, jlong targetWeapon);
jlong JNICALL getHeldWeapon(JNIEnv *env, jobject self, jlong target);
jlong JNICALL getDefaultWeapon(JNIEnv *env, jobject self, jlong target);
jboolean JNICALL swapDefaultWeapons(JNIEnv *env, jobject self, jlong jcreature, jlong jweapon, jlong jcontainer);
jboolean JNICALL isWeapon(JNIEnv *env, jobject self, jlong target);
jboolean JNICALL isDefaultWeapon(JNIEnv *env, jobject self, jlong target);
jfloat JNICALL getMinRange(JNIEnv *env, jobject self, jlong weaponId);
jfloat JNICALL getMaxRange(JNIEnv *env, jobject self, jlong weaponId);
jfloat JNICALL getAverageDamage(JNIEnv *env, jobject self, jlong weaponId);
jint JNICALL getWeaponType(JNIEnv *env, jobject self, jlong weaponId);
jint JNICALL getWeaponAttackType(JNIEnv *env, jobject self, jlong weaponId);
jint JNICALL getWeaponDamageType(JNIEnv *env, jobject self, jlong weapon);
jboolean JNICALL setWeaponDamageType(JNIEnv *env, jobject self, jlong weaponId, jint type);
jint JNICALL getWeaponMinDamage(JNIEnv *env, jobject self, jlong weapon);
jboolean JNICALL setWeaponMinDamage(JNIEnv *env, jobject self, jlong weapon, jint damage);
jint JNICALL getWeaponMaxDamage(JNIEnv *env, jobject self, jlong weapon);
jboolean JNICALL setWeaponMaxDamage(JNIEnv *env, jobject self, jlong weapon, jint damage);
jfloat JNICALL getWeaponAttackSpeed(JNIEnv *env, jobject self, jlong weapon);
jboolean JNICALL setWeaponAttackSpeed(JNIEnv *env, jobject self, jlong weapon, jfloat speed);
jobject JNICALL getWeaponRangeInfo(JNIEnv *env, jobject self, jlong weapon);
jboolean JNICALL setWeaponRangeInfo(JNIEnv *env, jobject self, jlong weapon, jobject info);
jfloat JNICALL getWeaponWoundChance(JNIEnv *env, jobject self, jlong weapon);
jboolean JNICALL setWeaponWoundChance(JNIEnv *env, jobject self, jlong weapon, jfloat chance);
jfloat JNICALL getWeaponDamageRadius(JNIEnv *env, jobject self, jlong weapon);
jboolean JNICALL setWeaponDamageRadius(JNIEnv *env, jobject self, jlong weapon, jfloat radius);
jfloat JNICALL getAudibleRange(JNIEnv *env, jobject self, jlong mob);
jint JNICALL getWeaponAttackCost(JNIEnv *env, jobject self, jlong weaponId);
jboolean JNICALL setWeaponAttackCost(JNIEnv *env, jobject self, jlong weaponId, jint cost);
jint JNICALL getWeaponAccuracy(JNIEnv *env, jobject self, jlong weaponId);
jboolean JNICALL setWeaponAccuracy(JNIEnv *env, jobject self, jlong weaponId, jint accuracy);
jint JNICALL getWeaponElementalType(JNIEnv *env, jobject self, jlong weaponId);
jboolean JNICALL setWeaponElementalType(JNIEnv *env, jobject self, jlong weaponId, jint type);
jint JNICALL getWeaponElementalValue(JNIEnv *env, jobject self, jlong weaponId);
jboolean JNICALL setWeaponElementalValue(JNIEnv *env, jobject self, jlong weaponId, jint value);
jboolean JNICALL isCombatEnabled(JNIEnv *env, jobject self);
jboolean JNICALL directDamage(JNIEnv *env, jobject self, jlong targetId, jint type, jint location, jint amount);
jboolean JNICALL directWeaponDamage(JNIEnv *env, jobject self, jlong targetId, jlong weaponId, jint amount, jint location);
jboolean JNICALL directAreaDamageObject(JNIEnv *env, jobject self, jlong targetId, jfloat radius, jint type, jint amount);
jboolean JNICALL directAreaDamageLocation(JNIEnv *env, jobject self, jobject center, jfloat radius, jint type, jint amount);
void JNICALL startCombat(JNIEnv *env, jobject self, jlong attacker, jlong defender);
void JNICALL startCombatWithAssist(JNIEnv *env, jobject self, jlong attacker, jlong defender);
void JNICALL stopCombat(JNIEnv *env, jobject self, jlong object);
jboolean JNICALL getCombatData(JNIEnv *env, jobject self, jlongArray attackers, jlongArray defenders, jobjectArray attackersData, jobjectArray defendersData, jobjectArray weaponsData);
jboolean JNICALL getWeaponData(JNIEnv *env, jobject self, jlong weapon, jobject weaponData);
jboolean JNICALL doDamage(JNIEnv *env, jobject self, jlong attacker, jlong defender, jlong weapon, jint damage, jint hitLocation);
jboolean JNICALL doDamageNoWeapon(JNIEnv *env, jobject self, jlong attacker, jlong defender, jint damage, jint hitLocation);
jboolean JNICALL doCombatResults(JNIEnv *env, jobject self, jstring animationId, jobject attackerResult, jobjectArray defenderResult);
jboolean JNICALL callDefenderCombatAction(JNIEnv *env, jobject self, jlongArray defenders, jintArray results, jlong attacker, jlong weapon);
void JNICALL setWantSawAttackTriggers(JNIEnv *env, jobject self, jlong obj, jboolean enable);
jboolean JNICALL addSlowDownEffect(JNIEnv *env, jobject self, jlong attacker, jlong defender, jfloat coneLength, jfloat coneAngle, jfloat slopeAngle, jfloat effectTime);
jboolean JNICALL removeSlowDownEffect(JNIEnv *env, jobject self, jlong attacker);
void JNICALL sendCombatSpam(JNIEnv *env, jobject self, jlong attacker, jlong defender, jlong weapon, jobject result, jobject attackName, jboolean sendToAttacker, jboolean sendToDefender, jboolean sendToBystanders, jint spamType);
void JNICALL sendCombatSpamWeaponString(JNIEnv *env, jobject self, jlong attacker, jlong defender, jobject weaponName, jobject result, jobject attackName, jboolean sendToAttacker, jboolean sendToDefender, jboolean sendToBystanders, jint spamType);
void JNICALL sendCombatSpamMessage(JNIEnv *env, jobject self, jlong attacker, jlong defender, jobject message, jboolean sendToAttacker, jboolean sendToDefender, jboolean sendToBystanders, jint spamType);
void JNICALL sendCombatSpamMessageCGP(JNIEnv *env, jobject self, jlong attacker, jlong defender, jobject message, jboolean sendToAttacker, jboolean sendToDefender, jboolean sendToBystanders, jboolean critical, jboolean glancing, jboolean proc, jint spamType);
void JNICALL sendCombatSpamMessageOob(JNIEnv *env, jobject self, jlong attacker, jlong defender, jstring oob, jboolean sendToAttacker, jboolean sendToDefender, jboolean sendToBystanders, jint spamType);
void JNICALL incrementKillMeter(JNIEnv *env, jobject self, jlong player, jint amount);
jint JNICALL getKillMeter(JNIEnv *env, jobject self, jlong player);
jboolean JNICALL overrideDefaultAttack(JNIEnv *env, jobject self, jlong player, jstring attack);
jboolean JNICALL removeDefaultAttackOverride(JNIEnv *env, jobject self, jlong player);
jstring JNICALL getDefaultAttackOverrideActionName(JNIEnv *env, jobject self, jlong player);
int const totalWildcards = 2;
std::string const s_wildcardReplacements[totalWildcards] = { "medium", "light" };
}
//========================================================================
// install
//========================================================================
bool ScriptMethodsCombatNamespace::install()
{
const JNINativeMethod NATIVES[] = {
#define JF(a,b,c) {a,b,(void*)(ScriptMethodsCombatNamespace::c)}
JF("_getCombatDuration", "(J)I", getCombatDuration),
JF("_getCurrentWeapon", "(J)J", getCurrentWeapon),
JF("_setCurrentWeapon", "(JJ)Z", setCurrentWeapon),
JF("_getHeldWeapon", "(J)J", getHeldWeapon),
JF("_getDefaultWeapon", "(J)J", getDefaultWeapon),
JF("_swapDefaultWeapons", "(JJJ)Z", swapDefaultWeapons),
JF("_isWeapon", "(J)Z", isWeapon),
JF("_isDefaultWeapon", "(J)Z", isDefaultWeapon),
JF("_getMinRange", "(J)F", getMinRange),
JF("_getMaxRange", "(J)F", getMaxRange),
JF("_getAverageDamage", "(J)F", getAverageDamage),
JF("_getWeaponType", "(J)I", getWeaponType),
JF("_getWeaponAttackType", "(J)I", getWeaponAttackType),
JF("_getWeaponDamageType", "(J)I", getWeaponDamageType),
JF("_setWeaponDamageType", "(JI)Z", setWeaponDamageType),
JF("_getWeaponMinDamage", "(J)I", getWeaponMinDamage),
JF("_setWeaponMinDamage", "(JI)Z", setWeaponMinDamage),
JF("_getWeaponMaxDamage", "(J)I", getWeaponMaxDamage),
JF("_setWeaponMaxDamage", "(JI)Z", setWeaponMaxDamage),
JF("_getWeaponAttackSpeed", "(J)F", getWeaponAttackSpeed),
JF("_setWeaponAttackSpeed", "(JF)Z", setWeaponAttackSpeed),
JF("_getWeaponRangeInfo", "(J)Lscript/base_class$range_info;", getWeaponRangeInfo),
JF("_setWeaponRangeInfo", "(JLscript/base_class$range_info;)Z", setWeaponRangeInfo),
JF("_getWeaponWoundChance", "(J)F", getWeaponWoundChance),
JF("_setWeaponWoundChance", "(JF)Z", setWeaponWoundChance),
JF("_getWeaponDamageRadius", "(J)F", getWeaponDamageRadius),
JF("_setWeaponDamageRadius", "(JF)Z", setWeaponDamageRadius),
JF("_getWeaponAudibleRange", "(J)F",getAudibleRange),
JF("_getWeaponAttackCost", "(J)I", getWeaponAttackCost),
JF("_setWeaponAttackCost", "(JI)Z", setWeaponAttackCost),
JF("_getWeaponAccuracy", "(J)I", getWeaponAccuracy),
JF("_setWeaponAccuracy", "(JI)Z", setWeaponAccuracy),
JF("_getWeaponElementalType", "(J)I", getWeaponElementalType),
JF("_setWeaponElementalType", "(JI)Z", setWeaponElementalType),
JF("_getWeaponElementalValue", "(J)I", getWeaponElementalValue),
JF("_setWeaponElementalValue", "(JI)Z", setWeaponElementalValue),
JF("isCombatEnabled", "()Z", isCombatEnabled),
JF("_damage", "(JIII)Z", directDamage),
JF("_damage", "(JJII)Z", directWeaponDamage),
JF("_damage", "(JFII)Z", directAreaDamageObject),
JF("damage", "(Lscript/location;FII)Z", directAreaDamageLocation),
JF("_startCombat", "(JJ)V", startCombat),
JF("_startCombatWithAssist", "(JJ)V", startCombatWithAssist),
JF("_stopCombat", "(J)V", stopCombat),
JF("__getCombatData", "([J[J[Lscript/combat_engine$attacker_data;[Lscript/combat_engine$defender_data;[Lscript/combat_engine$weapon_data;)Z", getCombatData),
JF("__getWeaponData", "(JLscript/combat_engine$weapon_data;)Z", getWeaponData),
JF("__doDamage", "(JJJII)Z", doDamage),
JF("__doDamageNoWeapon", "(JJII)Z", doDamageNoWeapon),
JF("doCombatResults", "(Ljava/lang/String;Lscript/base_class$attacker_results;[Lscript/base_class$defender_results;)Z", doCombatResults),
JF("_callDefenderCombatAction", "([J[IJJ)Z", callDefenderCombatAction),
JF("_setWantSawAttackTriggers", "(JZ)V", setWantSawAttackTriggers),
JF("_addSlowDownEffect", "(JJFFFF)Z", addSlowDownEffect),
JF("_removeSlowDownEffect", "(J)Z", removeSlowDownEffect),
JF("_sendCombatSpam", "(JJJLscript/combat_engine$hit_result;Lscript/string_id;ZZZI)V", sendCombatSpam),
JF("_sendCombatSpam", "(JJLscript/string_id;Lscript/combat_engine$hit_result;Lscript/string_id;ZZZI)V", sendCombatSpamWeaponString),
JF("_sendCombatSpamMessage", "(JJLscript/string_id;ZZZI)V", sendCombatSpamMessage),
JF("_sendCombatSpamMessageCGP", "(JJLscript/string_id;ZZZZZZI)V", sendCombatSpamMessageCGP),
JF("_sendCombatSpamMessageOob", "(JJLjava/lang/String;ZZZI)V", sendCombatSpamMessageOob),
JF("_incrementKillMeter", "(JI)V", incrementKillMeter),
JF("_getKillMeter", "(J)I", getKillMeter),
JF("_overrideDefaultAttack", "(JLjava/lang/String;)Z", overrideDefaultAttack),
JF("_removeDefaultAttackOverride", "(J)Z", removeDefaultAttackOverride),
JF("_getDefaultAttackOverrideActionName", "(J)Ljava/lang/String;", getDefaultAttackOverrideActionName)
};
return JavaLibrary::registerNatives(NATIVES, sizeof(NATIVES)/sizeof(NATIVES[0]));
}
//========================================================================
// local utility functions
//========================================================================
/**
* Fills in a Java combat_engine.weapon_data structure with data from a weapon.
*
* @param env Java environment
* @param weapon weapon to get the data from
* @param weaponData data to fill in
*/
void JavaLibrary::setupWeaponCombatData(JNIEnv *env, const WeaponObject * weapon,
jobject weaponData)
{
if (env == NULL || weaponData == NULL)
return;
if (weapon == NULL)
{
env->SetObjectField(weaponData, ms_fidCombatEngineWeaponDataId, NULL);
return;
}
LocalRefParam jweaponData(weaponData);
LocalRefPtr weaponId = getObjId(weapon->getNetworkId());
// set up base weapon data
setObjectField(jweaponData, ms_fidCombatEngineWeaponDataId, *weaponId);
setIntField(jweaponData, ms_fidCombatEngineWeaponDataMinDamage, weapon->getMinDamage());
setIntField(jweaponData, ms_fidCombatEngineWeaponDataMaxDamage, weapon->getMaxDamage());
setIntField(jweaponData, ms_fidCombatEngineWeaponDataWeaponType, weapon->getWeaponType());
setIntField(jweaponData, ms_fidCombatEngineWeaponDataAttackType, weapon->getAttackType());
setIntField(jweaponData, ms_fidCombatEngineWeaponDataDamageType, weapon->getDamageType());
setIntField(jweaponData, ms_fidCombatEngineWeaponDataElementalType, weapon->getElementalType());
setIntField(jweaponData, ms_fidCombatEngineWeaponDataElementalValue, weapon->getElementalValue());
setFloatField(jweaponData, ms_fidCombatEngineWeaponDataAttackSpeed, weapon->getAttackTime());
setFloatField(jweaponData, ms_fidCombatEngineWeaponDataWoundChance, weapon->getWoundChance());
setIntField(jweaponData, ms_fidCombatEngineWeaponDataAccuracy, weapon->getAccuracy());
setFloatField(jweaponData, ms_fidCombatEngineWeaponDataMinRange, weapon->getMinRange());
setFloatField(jweaponData, ms_fidCombatEngineWeaponDataMaxRange, weapon->getMaxRange());
setFloatField(jweaponData, ms_fidCombatEngineWeaponDataDamageRadius, weapon->getDamageRadius());
setIntField(jweaponData, ms_fidCombatEngineWeaponDataAttackCost, weapon->getAttackCost());
setBooleanField(jweaponData, ms_fidCombatEngineWeaponDataIsDisabled, weapon->isDisabled());
} // setupWeaponCombatData
//========================================================================
// class JavaLibrary JNI weapon callback methods
//========================================================================
jint JNICALL ScriptMethodsCombatNamespace::getCombatDuration(JNIEnv * /*env*/, jobject /*self*/, jlong object)
{
NetworkId const networkId(object);
TangibleObject const * const tangibleObject = TangibleObject::getTangibleObject(networkId);
if (tangibleObject == NULL)
{
return 0;
}
return tangibleObject->getCombatDuration();
}
/**
* Returns the current weapon a creature is using for combat.
*
* @param env Java environment
* @param self class calling this function
* @param target id of the creature
*
* @return the object id of the weapon, or NULL on error
*/
jlong JNICALL ScriptMethodsCombatNamespace::getCurrentWeapon(JNIEnv *env, jobject self, jlong target)
{
UNREF(self);
CreatureObject * creature = 0;
if (!JavaLibrary::getObject(target, creature))
return 0;
const WeaponObject * weapon = creature->getCurrentWeapon();
if (weapon == NULL)
return 0;
return (weapon->getNetworkId()).getValue();
} // JavaLibrary::getCurrentWeapon
/**
* Sets the weapon a creature will use for combat.
* @param target id of the object
* @param weapon id of the weapon
* @return JNI_TRUE on success, JNI_FALSE on fail
*/
jboolean JNICALL ScriptMethodsCombatNamespace::setCurrentWeapon(JNIEnv *env, jobject self, jlong target, jlong targetWeapon)
{
UNREF(self);
CreatureObject * creature = 0;
if (!JavaLibrary::getObject(target, creature))
return JNI_FALSE;
WeaponObject * weapon = 0;
if (!JavaLibrary::getObject(targetWeapon, weapon))
return JNI_FALSE;
creature->setCurrentWeapon(*weapon);
return JNI_TRUE;
} // JavaLibrary::setCurrentWeapon
/**
* Returns the current weapon a creature has equipped.
*
* @param env Java environment
* @param self class calling this function
* @param target id of the creature
*
* @return the object id of the weapon, or NULL on error
*/
jlong JNICALL ScriptMethodsCombatNamespace::getHeldWeapon(JNIEnv *env, jobject self, jlong target)
{
UNREF(self);
const CreatureObject * creature = 0;
if (!JavaLibrary::getObject(target, creature))
return 0;
const WeaponObject * weapon = creature->getReadiedWeapon();
if (weapon == NULL)
return 0;
return (weapon->getNetworkId()).getValue();
} // JavaLibrary::getHeldWeapon
/**
* Returns the default weapon of a creature.
*
* @param env Java environment
* @param self class calling this function
* @param target id of the creature
*
* @return the object id of the default weapon, or NULL on error
*/
jlong JNICALL ScriptMethodsCombatNamespace::getDefaultWeapon(JNIEnv *env, jobject self, jlong target)
{
UNREF(self);
const CreatureObject * creature = 0;
if (!JavaLibrary::getObject(target, creature))
return 0;
const WeaponObject * weapon = creature->getDefaultWeapon();
if (weapon == NULL)
return 0;
return (weapon->getNetworkId()).getValue();
} // JavaLibrary::getDefaultWeapon
/**
* Replaces the default weapon of a creature.
*
* @param env Java environment
* @param self class calling this function
* @param creature id of the creature
* @param weapon id of the new default weapon
* @param container id of the container to put the old weapon in
*
* @return true on success, false on error
*/
jboolean JNICALL ScriptMethodsCombatNamespace::swapDefaultWeapons(JNIEnv *env, jobject, jlong jcreature, jlong jweapon, jlong jcontainer)
{
CreatureObject *creature = 0;
if (!JavaLibrary::getObject(jcreature, creature))
return JNI_FALSE;
WeaponObject *newDefaultWeapon = 0;
if (!JavaLibrary::getObject(jweapon, newDefaultWeapon))
return JNI_FALSE;
ServerObject *weaponContainer = 0;
if (!JavaLibrary::getObject(jcontainer, weaponContainer))
return JNI_FALSE;
if (!creature->swapDefaultWeapons(*newDefaultWeapon, *weaponContainer))
return JNI_FALSE;
return JNI_TRUE;
}
/**
* Tests to see if an object is a weapon.
*
* @param env Java environment
* @param self class calling this function
* @param target id of object we want to check
*
* @return true if the object is a weapon, false if not
*/
jboolean JNICALL ScriptMethodsCombatNamespace::isWeapon(JNIEnv *env, jobject self, jlong target)
{
UNREF(self);
const WeaponObject *weapon = 0;
if (!JavaLibrary::getObject(target, weapon))
return JNI_FALSE;
return JNI_TRUE;
} // JavaLibrary::isWeapon
/**
* Tests to see if an object is a default weapon.
*
* @param env Java environment
* @param self class calling this function
* @param target id of object we want to check
*
* @return true if the object is a default weapon, false if not
*/
jboolean JNICALL ScriptMethodsCombatNamespace::isDefaultWeapon(JNIEnv *env, jobject self, jlong target)
{
UNREF(self);
const WeaponObject *weapon = 0;
if (!JavaLibrary::getObject(target, weapon))
return JNI_FALSE;
const CreatureObject * owner = dynamic_cast<const CreatureObject *>(ContainerInterface::getContainedByObject(*weapon));
if (owner == NULL || owner->getDefaultWeapon() != weapon)
return JNI_FALSE;
return JNI_TRUE;
} // JavaLibrary::isDefaultWeapon
/**
* Returns the minimum attack range of a weapon.
*
* @param env Java environment
* @param self class calling this function
* @param weaponId id of weapon
*
* @return the range, or -1 on error
*/
jfloat JNICALL ScriptMethodsCombatNamespace::getMinRange(JNIEnv *env, jobject self, jlong weaponId)
{
UNREF(self);
const WeaponObject *weapon = NULL;
if (!JavaLibrary::getObject(weaponId, weapon))
return -1.0f;
jfloat range = weapon->getMinRange();
return range;
} // JavaLibrary::getMinRange
/**
* Returns the maximum attack range of a weapon.
*
* @param env Java environment
* @param self class calling this function
* @param weaponId id of weapon
*
* @return the range, or -1 on error
*/
jfloat JNICALL ScriptMethodsCombatNamespace::getMaxRange(JNIEnv *env, jobject self, jlong weaponId)
{
UNREF(self);
const WeaponObject *weapon = NULL;
if (!JavaLibrary::getObject(weaponId, weapon))
return -1.0f;
jfloat range = weapon->getMaxRange();
return range;
} // JavaLibrary::getMaxRange
/**
* Returns the average damage a weapon will do
*
* @param env Java environment
* @param self class calling this function
* @param weaponId id of weapon
*
* @return the damage, or 0 on error
*/
jfloat JNICALL ScriptMethodsCombatNamespace::getAverageDamage(JNIEnv *env, jobject self, jlong weaponId)
{
UNREF(self);
const WeaponObject *weapon = NULL;
if (!JavaLibrary::getObject(weaponId, weapon))
return 0;
jfloat damage = weapon->getMinDamage() + (weapon->getMaxDamage() -
weapon->getMinDamage()) / 2.0f;
return damage;
} // JavaLibrary::getAverageDamage
/**
* Returns a weapon's type.
*
* @param env Java environment
* @param self class calling this function
* @param weaponId id of weapon
*
* @return the type, or -1 on error
*/
jint JNICALL ScriptMethodsCombatNamespace::getWeaponType(JNIEnv *env, jobject self, jlong weaponId)
{
UNREF(self);
const WeaponObject *weapon = NULL;
if (!JavaLibrary::getObject(weaponId, weapon))
return -1;
jint type = weapon->getWeaponType();
return type;
} // JavaLibrary::getWeaponType
/**
* Returns a weapon's attack type.
*
* @param env Java environment
* @param self class calling this function
* @param weaponId id of weapon
*
* @return the type, or -1 on error
*/
jint JNICALL ScriptMethodsCombatNamespace::getWeaponAttackType(JNIEnv *env, jobject self, jlong weaponId)
{
UNREF(self);
const WeaponObject *weapon = NULL;
if (!JavaLibrary::getObject(weaponId, weapon))
return -1;
jint type = weapon->getAttackType();
return type;
} // JavaLibrary::getWeaponAttackType
/**
* Gets the damage type of a weapon.
*
* @param weapon the id of the weapon
*
* @return the damage type, or -1 on error
*/
jint JNICALL ScriptMethodsCombatNamespace::getWeaponDamageType(JNIEnv *env, jobject self, jlong weaponId)
{
UNREF(self);
const WeaponObject *weapon = NULL;
if (!JavaLibrary::getObject(weaponId, weapon))
return -1;
jint type = weapon->getDamageType();
return type;
} // JavaLibrary::getWeaponDamageType
/**
* Sets the ddamage type for a weapon.
*
* @param env Java environment
* @param self class calling this function
* @param weaponId the id of the weapon
* @param cost damage type for the weapon
*
* @return true on success, false if there was an error
*/
jboolean JNICALL ScriptMethodsCombatNamespace::setWeaponDamageType(JNIEnv *env, jobject self, jlong weaponId, jint type)
{
UNREF(self);
WeaponObject *weapon = 0;
if (!JavaLibrary::getObject(weaponId, weapon))
return JNI_FALSE;
weapon->setDamageType(type);
return JNI_TRUE;
} // JavaLibrary::setWeaponDamageType
/**
* Gets the minimum damage a weapon does.
*
* @param env Java environment
* @param self class calling this function
* @param weaponId the id of the weapon
*
* @return the damage, or -1 on error
*/
jint JNICALL ScriptMethodsCombatNamespace::getWeaponMinDamage(JNIEnv *env, jobject self, jlong weaponId)
{
UNREF(self);
const WeaponObject *weapon = NULL;
if (!JavaLibrary::getObject(weaponId, weapon))
return -1;
jint damage = weapon->getMinDamage();
return damage;
} // JavaLibrary::getWeaponMinDamage
/**
* Sets the minimum damage a weapon does.
*
* @param env Java environment
* @param self class calling this function
* @param weaponId the id of the weapon
* @param damage the minimum damage
*
* @return true on success, false if there was an error
*/
jboolean JNICALL ScriptMethodsCombatNamespace::setWeaponMinDamage(JNIEnv *env, jobject self, jlong weaponId, jint damage)
{
UNREF(self);
WeaponObject *weapon = 0;
if (!JavaLibrary::getObject(weaponId, weapon))
return JNI_FALSE;
if (damage < 0)
return JNI_FALSE;
weapon->setMinDamage(damage);
return JNI_TRUE;
} // JavaLibrary::setWeaponMinDamage
/**
* Gets the maximum damage a weapon does.
*
* @param env Java environment
* @param self class calling this function
* @param weaponId the id of the weapon
*
* @return the damage, or -1 on error
*/
jint JNICALL ScriptMethodsCombatNamespace::getWeaponMaxDamage(JNIEnv *env, jobject self, jlong weaponId)
{
UNREF(self);
const WeaponObject *weapon = NULL;
if (!JavaLibrary::getObject(weaponId, weapon))
return -1;
jint damage = weapon->getMaxDamage();
return damage;
} // JavaLibrary::getWeaponMaxDamage
/**
* Sets the maximum damage a weapon does.
*
* @param env Java environment
* @param self class calling this function
* @param weaponId the id of the weapon
* @param damage the maximum damage
*
* @return true on success, false if there was an error
*/
jboolean JNICALL ScriptMethodsCombatNamespace::setWeaponMaxDamage(JNIEnv *env, jobject self, jlong weaponId, jint damage)
{
UNREF(self);
WeaponObject *weapon = 0;
if (!JavaLibrary::getObject(weaponId, weapon))
return JNI_FALSE;
if (damage < 0)
return JNI_FALSE;
weapon->setMaxDamage(damage);
return JNI_TRUE;
} // JavaLibrary::setWeaponMaxDamage
/**
* Gets the attack speed of a weapon.
*
* @param env Java environment
* @param self class calling this function
* @param weaponId the id of the weapon
*
* @return the attack speed, or -1 on error
*/
jfloat JNICALL ScriptMethodsCombatNamespace::getWeaponAttackSpeed(JNIEnv *env, jobject self, jlong weaponId)
{
UNREF(self);
const WeaponObject *weapon = NULL;
if (!JavaLibrary::getObject(weaponId, weapon))
return -1.0f;
jfloat speed = weapon->getAttackTime();
return speed;
} // JavaLibrary::getWeaponAttackSpeed
/**
* Sets the attack speed of a weapon.
*
* @param env Java environment
* @param self class calling this function
* @param weaponId the id of the weapon
* @param speed the attack speed
*
* @return true on success, false if there was an error
*/
jboolean JNICALL ScriptMethodsCombatNamespace::setWeaponAttackSpeed(JNIEnv *env, jobject self, jlong weaponId, jfloat speed)
{
UNREF(self);
WeaponObject *weapon = 0;
if (!JavaLibrary::getObject(weaponId, weapon))
return JNI_FALSE;
if (speed < 0)
return JNI_FALSE;
weapon->setAttackTime(speed);
return JNI_TRUE;
} // JavaLibrary::setWeaponAttackSpeed
/**
* Gets the % change that a weapon will cause a wound.
*
* @param env Java environment
* @param self class calling this function
* @param weaponId the id of the weapon
*
* @return the wound chance, or -1 on error
*/
jfloat JNICALL ScriptMethodsCombatNamespace::getWeaponWoundChance(JNIEnv *env, jobject self, jlong weaponId)
{
UNREF(self);
const WeaponObject *weapon = NULL;
if (!JavaLibrary::getObject(weaponId, weapon))
return -1.0f;
jfloat chance = weapon->getWoundChance();
return chance;
} // JavaLibrary::getWeaponWoundChance
/**
* Gets the range info of a weapon.
*
* @param env Java environment
* @param self class calling this function
* @param weaponId the id of the weapon
*
* @return the range info, or null on error
*/
jobject JNICALL ScriptMethodsCombatNamespace::getWeaponRangeInfo(JNIEnv *env, jobject self, jlong weaponId)
{
UNREF(self);
const WeaponObject *weapon = NULL;
if (!JavaLibrary::getObject(weaponId, weapon))
return 0;
LocalRefPtr range = allocObject(JavaLibrary::getClsBaseClassRangeInfo());
if (range == LocalRef::cms_nullPtr)
return 0;
setFloatField(*range, JavaLibrary::getFidBaseClassRangeInfoMinRange(), weapon->getMinRange());
setFloatField(*range, JavaLibrary::getFidBaseClassRangeInfoMaxRange(), weapon->getMaxRange());
return range->getReturnValue();
} // JavaLibrary::getWeaponRangeInfo
/**
* Sets all the range info of a weapon.
*
* @param env Java environment
* @param self class calling this function
* @param weaponId the id of the weapon
* @param info the new range info
*
* @return true on success, false if there was an error
*/
jboolean JNICALL ScriptMethodsCombatNamespace::setWeaponRangeInfo(JNIEnv *env, jobject self, jlong weaponId, jobject info)
{
UNREF(self);
if (info == 0)
return JNI_FALSE;
WeaponObject *weapon = 0;
if (!JavaLibrary::getObject(weaponId, weapon))
return JNI_FALSE;
weapon->setMinRange(env->GetFloatField(info, JavaLibrary::getFidBaseClassRangeInfoMinRange()));
weapon->setMaxRange(env->GetFloatField(info, JavaLibrary::getFidBaseClassRangeInfoMaxRange()));
return JNI_TRUE;
} // JavaLibrary::setWeaponRangeInfo
/**
* Sets the % change that a weapon will cause a wound.
*
* @param env Java environment
* @param self class calling this function
* @param weaponId the id of the weapon
* @param chance the wound % chance
*
* @return true on success, false if there was an error
*/
jboolean JNICALL ScriptMethodsCombatNamespace::setWeaponWoundChance(JNIEnv *env, jobject self, jlong weaponId, jfloat chance)
{
UNREF(self);
WeaponObject *weapon = 0;
if (!JavaLibrary::getObject(weaponId, weapon))
return JNI_FALSE;
if (chance < 0)
return JNI_FALSE;
weapon->setWoundChance(chance);
return JNI_TRUE;
} // JavaLibrary::setWeaponWoundChance
/**
* Gets the damage radius for area-effect weapons.
*
* @param env Java environment
* @param self class calling this function
* @param weaponId the id of the weapon
*
* @return the damage radius, or -1 on error
*/
jfloat JNICALL ScriptMethodsCombatNamespace::getWeaponDamageRadius(JNIEnv *env, jobject self, jlong weaponId)
{
UNREF(self);
const WeaponObject *weapon = NULL;
if (!JavaLibrary::getObject(weaponId, weapon))
return -1.0f;
jfloat radius = weapon->getDamageRadius();
return radius;
} // JavaLibrary::getWeaponDamageRadius
/**
* Sets the damage radius for area-effect weapons.
*
* @param env Java environment
* @param self class calling this function
* @param weaponId the id of the weapon
* @param radius the damage radius
*
* @return true on success, false if there was an error
*/
jboolean JNICALL ScriptMethodsCombatNamespace::setWeaponDamageRadius(JNIEnv *env, jobject self, jlong weaponId, jfloat radius)
{
UNREF(self);
WeaponObject *weapon = 0;
if (!JavaLibrary::getObject(weaponId, weapon))
return JNI_FALSE;
if (radius < 0)
return JNI_FALSE;
weapon->setDamageRadius(radius);
return JNI_TRUE;
} // JavaLibrary::setWeaponDamageRadius
/**
*
*/
jfloat JNICALL ScriptMethodsCombatNamespace::getAudibleRange(JNIEnv *env, jobject self, jlong weaponId)
{
const WeaponObject *weapon = NULL;
if (!JavaLibrary::getObject(weaponId, weapon))
return -1;
jfloat range = weapon->getAudibleRange();
return range;
}
/**
* Gets the attack cost for a weapon.
*
* @param env Java environment
* @param self class calling this function
* @param weaponId the id of the weapon
*
* @return the attack costs, or 0 on error
*/
jint JNICALL ScriptMethodsCombatNamespace::getWeaponAttackCost(JNIEnv *env, jobject self, jlong weaponId)
{
UNREF(self);
const WeaponObject *weapon = NULL;
if (!JavaLibrary::getObject(weaponId, weapon))
return 0;
jint cost = weapon->getAttackCost();
return cost;
} // JavaLibrary::getWeaponAttackCost
/**
* Sets the attack cost for a weapon.
*
* @param env Java environment
* @param self class calling this function
* @param weaponId the id of the weapon
* @param cost attack cost for the weapon
*
* @return true on success, false if there was an error
*/
jboolean JNICALL ScriptMethodsCombatNamespace::setWeaponAttackCost(JNIEnv *env, jobject self, jlong weaponId, jint cost)
{
UNREF(self);
WeaponObject *weapon = 0;
if (!JavaLibrary::getObject(weaponId, weapon))
return JNI_FALSE;
weapon->setAttackCost(cost);
return JNI_TRUE;
} // JavaLibrary::setWeaponAttackCost
/**
* Gets the accuracy for a weapon.
*
* @param env Java environment
* @param self class calling this function
* @param weaponId the id of the weapon
*
* @return the accuracy, or 0 on error
*/
jint JNICALL ScriptMethodsCombatNamespace::getWeaponAccuracy(JNIEnv *env, jobject self, jlong weaponId)
{
UNREF(self);
const WeaponObject *weapon = NULL;
if (!JavaLibrary::getObject(weaponId, weapon))
return 0;
jint accuracy = weapon->getAccuracy();
return accuracy;
} // JavaLibrary::getWeaponAccuracy
/**
* Sets the accuracy for a weapon.
*
* @param env Java environment
* @param self class calling this function
* @param weaponId the id of the weapon
* @param accuracy accuracy for the weapon
*
* @return true on success, false if there was an error
*/
jboolean JNICALL ScriptMethodsCombatNamespace::setWeaponAccuracy(JNIEnv *env, jobject self, jlong weaponId, jint accuracy)
{
UNREF(self);
WeaponObject *weapon = 0;
if (!JavaLibrary::getObject(weaponId, weapon))
return JNI_FALSE;
weapon->setAccuracy(accuracy);
return JNI_TRUE;
} // JavaLibrary::setWeaponAccuracy
/**
* Gets the elemantal damage type of a weapon.
*
* @param env Java environment
* @param self class calling this function
* @param weaponId the id of the weapon
*
* @return the elemantal damage type, or 0 on error
*/
jint JNICALL ScriptMethodsCombatNamespace::getWeaponElementalType(JNIEnv *env, jobject self, jlong weaponId)
{
UNREF(self);
const WeaponObject *weapon = NULL;
if (!JavaLibrary::getObject(weaponId, weapon))
return 0;
jint eleType = weapon->getElementalType();
return eleType;
} // JavaLibrary::getWeaponElementalType
/**
* Sets the elemental damage type for a weapon.
*
* @param env Java environment
* @param self class calling this function
* @param weaponId the id of the weapon
* @param cost elemental damage type for the weapon
*
* @return true on success, false if there was an error
*/
jboolean JNICALL ScriptMethodsCombatNamespace::setWeaponElementalType(JNIEnv *env, jobject self, jlong weaponId, jint type)
{
UNREF(self);
WeaponObject *weapon = 0;
if (!JavaLibrary::getObject(weaponId, weapon))
return JNI_FALSE;
weapon->setElementalType(type);
return JNI_TRUE;
} // JavaLibrary::setWeaponElementalType
/**
* Gets the elemantal damage value of a weapon.
*
* @param env Java environment
* @param self class calling this function
* @param weaponId the id of the weapon
*
* @return the elemantal damage value, or 0 on error
*/
jint JNICALL ScriptMethodsCombatNamespace::getWeaponElementalValue(JNIEnv *env, jobject self, jlong weaponId)
{
UNREF(self);
const WeaponObject *weapon = NULL;
if (!JavaLibrary::getObject(weaponId, weapon))
return 0;
jint value = weapon->getElementalValue();
return value;
} // JavaLibrary::getWeaponElementalValue
/**
* Sets the elemental damage value for a weapon.
*
* @param env Java environment
* @param self class calling this function
* @param weaponId the id of the weapon
* @param cost elemental damage value for the weapon
*
* @return true on success, false if there was an error
*/
jboolean JNICALL ScriptMethodsCombatNamespace::setWeaponElementalValue(JNIEnv *env, jobject self, jlong weaponId, jint value)
{
UNREF(self);
WeaponObject *weapon = 0;
if (!JavaLibrary::getObject(weaponId, weapon))
return JNI_FALSE;
weapon->setElementalValue(value);
return JNI_TRUE;
} // JavaLibrary::setWeaponElementalValue
//========================================================================
// class JavaLibrary JNI combat callback methods
//========================================================================
/**
* Returns if the combat engine is enabled.
*
* @param env Java environment
* @param self class calling this function
*
* @return JNI_TRUE if combat is enabled, JNI_FALSE if not
*/
jboolean JNICALL ScriptMethodsCombatNamespace::isCombatEnabled(JNIEnv *env, jobject self)
{
UNREF(env);
UNREF(self);
if (ConfigServerGame::getDisableCombat())
return JNI_FALSE;
return JNI_TRUE;
} // JavaLibrary::isCombatEnabled
/**
* Applies damage to an object.
*
* @param env Java environment
* @param self class calling this function
* @param targetId id of the object to damage
* @param type damage type being done
* @param location the hit location of the damage
* @param amount amount of damage to do
*
* @return the true on success, false on error
*/
jboolean JNICALL ScriptMethodsCombatNamespace::directDamage(JNIEnv *env, jobject self, jlong targetId, jint type, jint location, jint amount)
{
UNREF(self);
TangibleObject *target = 0;
if (!JavaLibrary::getObject(targetId, target))
return JNI_FALSE;
// make sure the parameters are valid
if (type < ServerObjectTemplate::DT_kinetic ||
type > ServerObjectTemplate::DamageType_Last)
{
return JNI_FALSE;
}
ServerWeaponObjectTemplate::DamageType damageType = static_cast<ServerObjectTemplate::DamageType>(type);
CombatEngine::damage(*target, damageType, static_cast<uint16>(location), amount);
return JNI_TRUE;
} // JavaLibrary::directDamage
/**
* Applies weapon-based damage to an object.
*
* @param env Java environment
* @param self class calling this function
* @param targetId id of the object to damage
* @param weaponId id of the weapon doing the damage
* @param amount amount of damage to do
* @param location where to do the damage
*
* @return the true on success, false on error
*/
jboolean JNICALL ScriptMethodsCombatNamespace::directWeaponDamage(JNIEnv *env, jobject self, jlong targetId, jlong weaponId, jint amount, jint location)
{
UNREF(self);
TangibleObject *target = 0;
if (!JavaLibrary::getObject(targetId, target))
return JNI_FALSE;
WeaponObject * weapon = 0;
if (!JavaLibrary::getObject(weaponId, weapon))
return JNI_FALSE;
CombatEngine::damage(*target, *weapon, amount, location);
return JNI_TRUE;
} // JavaLibrary::directWeaponDamage
/**
* Applies damage to all objects in a given area.
*
* @param env Java environment
* @param self class calling this function
* @param targetId id of the object to use as the center of the damage area
* @param radius radius of the damage area
* @param type damage type being done
* @param amount amount of damage to do
*
* @return the true on success, false on error
*/
jboolean JNICALL ScriptMethodsCombatNamespace::directAreaDamageObject(JNIEnv *env, jobject self, jlong targetId, jfloat radius, jint type, jint amount)
{
UNREF(self);
TangibleObject *target = 0;
if (!JavaLibrary::getObject(targetId, target))
return JNI_FALSE;
// make sure the damage type and subtype are valid
if (type < ServerObjectTemplate::DT_kinetic ||
type > ServerObjectTemplate::DamageType_Last)
{
return JNI_FALSE;
}
ServerWeaponObjectTemplate::DamageType damageType = static_cast<
ServerWeaponObjectTemplate::DamageType>(type);
CombatEngine::damage(target->getPosition_w(), radius, damageType, amount);
return JNI_TRUE;
} // JavaLibrary::directAreaDamageObject
/**
* Applies damage to all objects in a given area.
*
* @param env Java environment
* @param self class calling this function
* @param center the center of the damage area
* @param radius radius of the damage area
* @param type damage type being done
* @param amount amount of damage to do
*
* @return the true on success, false on error
*/
jboolean JNICALL ScriptMethodsCombatNamespace::directAreaDamageLocation(JNIEnv *env, jobject self,
jobject center, jfloat radius, jint type, jint amount)
{
UNREF(self);
if (center == 0)
return JNI_FALSE;
// @todo: can center.area be a different planet that the one this gameserver
// handles?
Vector centerPos;
if (!ScriptConversion::convertWorld(center, centerPos))
return JNI_FALSE;
// make sure the damage type and subtype are valid
if (type < ServerObjectTemplate::DT_kinetic ||
type > ServerObjectTemplate::DamageType_Last)
{
return JNI_FALSE;
}
ServerWeaponObjectTemplate::DamageType damageType = static_cast<
ServerWeaponObjectTemplate::DamageType>(type);
CombatEngine::damage(centerPos, radius, damageType, amount);
return JNI_TRUE;
} // JavaLibrary::directAreaDamageLocation
void _startCombat(char const * const functionName, jlong attacker, jlong defender, bool const assist)
{
NetworkId const attackerId(attacker);
TangibleObject * const attackerTangibleObject = TangibleObject::getTangibleObject(attackerId);
if (attackerTangibleObject == NULL)
{
JAVA_THROW_SCRIPT_EXCEPTION(true, ("ScriptMethodsCombat::%s() Unable to resolve the attacker(%s) to a TangibleObject.", functionName, attackerId.getValueString().c_str()));
return;
}
NetworkId const defenderId(defender);
TangibleObject * const defenderTangibleObject = TangibleObject::getTangibleObject(defenderId);
if (defenderTangibleObject == NULL)
{
JAVA_THROW_SCRIPT_EXCEPTION(true, ("ScriptMethodsCombat::%s() attacker(%s) Unable to resolve the defender(%s) to a TangibleObject.", functionName, attackerId.getValueString().c_str(), defenderId.getValueString().c_str()));
return;
}
if (attackerId == defenderId)
{
JAVA_THROW_SCRIPT_EXCEPTION(true, ("ScriptMethodsCombat::%s() The attacker(%s) is trying to start combat with himself.", functionName, attackerTangibleObject->getDebugInformation().c_str()));
return;
}
// Do not reset the attacker's hate list timer if the defender is already in the hate list
if (!attackerTangibleObject->isOnHateList(defenderId))
{
float const hate = assist ? 1.0f : 0.0f;
attackerTangibleObject->addHate(defenderId, hate);
}
// If the defender is a player, immediatelly let them know they are being attacked. This check is only for players
// because sending an AI on an AI (pets) instantly causes both parties to enter combat. That behavior is not
// desired because a pet could pull a AI from any distance without the pet having to attack the AI or get within
// the AI's aggro range.
if ( defenderTangibleObject->isPlayerControlled()
&& !defenderTangibleObject->isOnHateList(attackerId))
{
float const hate = assist ? 1.0f : 0.0f;
defenderTangibleObject->addHate(attackerId, hate);
}
}
/**
* Puts the attacker in combat towards the defender
*
* @param env Java environment
* @param self class calling this function
* @param attacker the object you want to start combat
* @param defender the object you want the attacker to be in combat towards
*
*/
void JNICALL ScriptMethodsCombatNamespace::startCombat(JNIEnv * /*env*/, jobject /*self*/, jlong attacker, jlong defender)
{
_startCombat("startCombat", attacker, defender, false);
}
/**
* Puts the attacker in combat towards the defender while notifying the nearby attacker's
* friends of the defender.
*
* @param env Java environment
* @param self class calling this function
* @param attacker the object you want to start combat
* @param target the object you want the attacker to be in combat towards
*
*/
void JNICALL ScriptMethodsCombatNamespace::startCombatWithAssist(JNIEnv * /*env*/, jobject /*self*/, jlong attacker, jlong defender)
{
_startCombat("startCombatWithAssist", attacker, defender, true);
}
/**
* Removes the object from combat
*
* @param env Java environment
* @param self class calling this function
* @param object the object you want to stop combat
*
*/
void JNICALL ScriptMethodsCombatNamespace::stopCombat(JNIEnv * /*env*/, jobject /*self*/, jlong object)
{
NetworkId const objectId(object);
TangibleObject * const tangibleObject = TangibleObject::getTangibleObject(objectId);
if (tangibleObject == NULL)
{
return;
}
tangibleObject->clearHateList();
}
// ------------------------------------------------------------------------------------
/**
* Gets data needed for combat for given attackers and defenders.
*
* @param env Java environment
* @param self class calling this function
* @param attackers ids of the attackers we want data for
* @param defenders ids of the defenders we want data for
* @param attackerData data for each attacker
* @param defenderData data for each defender
* @param weaponData data for each attackers' weapon
*
* @return JNI_TRUE on success, JNI_FALSE on error
*/
jboolean JNICALL ScriptMethodsCombatNamespace::getCombatData(JNIEnv *env, jobject self, jlongArray attackers, jlongArray defenders, jobjectArray attackersData, jobjectArray defendersData, jobjectArray weaponsData)
{
int i;
UNREF(self);
int attackerCount = 0;
int defenderCount = 0;
if (attackers != NULL)
attackerCount = env->GetArrayLength(attackers);
if (defenders != NULL)
defenderCount = env->GetArrayLength(defenders);
// get the attacker and weapon data
for (i = 0; i < attackerCount; ++i)
{
jlong attackerId;
env->GetLongArrayRegion(attackers, i, 1, &attackerId);
LocalRefPtr attackerData = getObjectArrayElement(LocalObjectArrayRefParam(attackersData), i);
LocalRefPtr weaponData = getObjectArrayElement(LocalObjectArrayRefParam(weaponsData), i);
if (!attackerId)
{
WARNING(true, ("JavaLibrary::getCombatData got null attacker id"));
return JNI_FALSE;
}
if (attackerData == LocalRef::cms_nullPtr)
{
WARNING(true, ("JavaLibrary::getCombatData got null attacker data"));
return JNI_FALSE;
}
if (weaponData == LocalRef::cms_nullPtr)
{
WARNING(true, ("JavaLibrary::getCombatData got null weapon data"));
return JNI_FALSE;
}
// set up the attacker data
const TangibleObject * attacker = NULL;
if (!JavaLibrary::getObject(attackerId, attacker))
{
WARNING(true, ("JavaLibrary::getCombatData cannot get attacker object"));
return JNI_FALSE;
}
// get the attacker's position in local and world coordinates
LocalRefPtr location;
LocalRefPtr worldLocation;
const Object * attackerCell = ContainerInterface::getContainedByObject(*attacker);
ScriptConversion::convert(attacker->getPosition_p(), attacker->getSceneId(),
attackerCell ? attackerCell->getNetworkId() : NetworkId::cms_invalid,
location);
if (location.get() == NULL || location == LocalRef::cms_nullPtr)
{
WARNING(true, ("JavaLibrary::getCombatData cannot convert local position "
"of attacker %s to Java", attacker->getNetworkId().getValueString().c_str()));
return JNI_FALSE;
}
if (attacker->isInWorldCell())
worldLocation = location;
else
{
ScriptConversion::convert(attacker->getPosition_w(), attacker->getSceneId(),
CellProperty::getWorldCellProperty()->getOwner().getNetworkId(),
worldLocation);
if (worldLocation.get() == NULL || worldLocation == LocalRef::cms_nullPtr)
{
WARNING(true, ("JavaLibrary::getCombatData cannot convert world position "
"of attacker %s to Java", attacker->getNetworkId().getValueString().c_str()));
return JNI_FALSE;
}
}
const WeaponObject * weapon = NULL;
bool isCreature = false;
int posture = 0;
int locomotion = 0;
int weaponSkill = 0;
int aims = 0;
const CreatureObject * creature = dynamic_cast<const CreatureObject *>(attacker);
if (creature != NULL)
{
isCreature = true;
posture = creature->getPosture();
locomotion = creature->getLocomotion();
weapon = (const_cast<CreatureObject *>(creature))->getCurrentWeapon();
}
else
{
weapon = dynamic_cast<const WeaponObject *>(attacker);
}
CombatEngineData::CombatData const * combatData = attacker->getCombatData();
if (combatData != NULL)
{
aims = combatData->attackData.aims;
}
setObjectField(*attackerData, JavaLibrary::getFidCombatEngineCombatantDataPos(), *location);
setObjectField(*attackerData, JavaLibrary::getFidCombatEngineCombatantDataWorldPos(), *worldLocation);
setFloatField(*attackerData, JavaLibrary::getFidCombatEngineCombatantDataRadius(), attacker->getRadius());
setBooleanField(*attackerData, JavaLibrary::getFidCombatEngineCombatantDataIsCreature(), isCreature);
setIntField(*attackerData, JavaLibrary::getFidCombatEngineCombatantDataPosture(), posture);
setIntField(*attackerData, JavaLibrary::getFidCombatEngineCombatantDataLocomotion(), locomotion);
setIntField(*attackerData, JavaLibrary::getFidCombatEngineCombatantDataScriptMod(), 0);
setIntField(*attackerData, JavaLibrary::getFidCombatEngineAttackerDataWeaponSkill(), weaponSkill);
setIntField(*attackerData, JavaLibrary::getFidCombatEngineAttackerDataAims(), aims);
// set up the weapon data
JavaLibrary::setupWeaponCombatData(env, weapon, weaponData->getValue());
}
// get the defender data
for (i = 0; i < defenderCount; ++i)
{
jlong defenderId;
env->GetLongArrayRegion(defenders, i, 1, &defenderId);
LocalRefPtr defenderData = getObjectArrayElement(LocalObjectArrayRefParam(defendersData), i);
if (!defenderId)
{
WARNING(true, ("JavaLibrary::getCombatData got null defender id"));
return JNI_FALSE;
}
if (defenderData == LocalRef::cms_nullPtr)
{
WARNING(true, ("JavaLibrary::getCombatData got null defender data"));
return JNI_FALSE;
}
// set up the defender data
const TangibleObject * defender = NULL;
if (!JavaLibrary::getObject(defenderId, defender))
{
WARNING(true, ("JavaLibrary::getCombatData cannot get defender object"));
return JNI_FALSE;
}
// get the defender's position in local and world coordinates
LocalRefPtr location;
LocalRefPtr worldLocation;
const Object * defenderCell = ContainerInterface::getContainedByObject(*defender);
ScriptConversion::convert(defender->getPosition_p(), defender->getSceneId(),
defenderCell ? defenderCell->getNetworkId() : NetworkId::cms_invalid,
location);
if (location.get() == NULL || location == LocalRef::cms_nullPtr)
{
WARNING(true, ("JavaLibrary::getCombatData cannot convert local position "
"of defender %s to Java", defender->getNetworkId().getValueString().c_str()));
return JNI_FALSE;
}
if (defender->isInWorldCell())
worldLocation = location;
else
{
ScriptConversion::convert(defender->getPosition_w(), defender->getSceneId(),
CellProperty::getWorldCellProperty()->getOwner().getNetworkId(),
worldLocation);
if (worldLocation.get() == NULL || worldLocation == LocalRef::cms_nullPtr)
{
WARNING(true, ("JavaLibrary::getCombatData cannot convert world position "
"of defender %s to Java", defender->getNetworkId().getValueString().c_str()));
return JNI_FALSE;
}
}
bool isCreature = false;
int posture = 0;
int locomotion = 0;
int combatSkeleton = defender->getCombatSkeleton();
int cover = 0;
const CreatureObject * creature = dynamic_cast<const CreatureObject *>(defender);
if (creature != NULL)
{
isCreature = true;
posture = creature->getPosture();
locomotion = creature->getLocomotion();
cover = creature->getCover();
}
// set the defender's hit location chances
const ConfigCombatEngine::SkeletonAttackMod & attackMods = ConfigCombatEngine::getSkeletonAttackMod(static_cast<ServerTangibleObjectTemplate::CombatSkeleton>(defender->getCombatSkeleton()));
int numBones = attackMods.numHitLocations;
if (numBones == 0)
{
WARNING_STRICT_FATAL(true, ("JavaLibrary::getCombatData, defender "
"combat skeleton %d returned 0 bones!", combatSkeleton));
return JNI_FALSE;
}
LocalIntArrayRefPtr chances = createNewIntArray(numBones);
if (chances == LocalIntArrayRef::cms_nullPtr)
return JNI_FALSE;
std::vector<jint> hitChances;
for (int j = 0; j < numBones; ++j)
hitChances.push_back(attackMods.attackMods[j].toHitChance);
setIntArrayRegion(*chances, 0, numBones, &hitChances[0]);
setObjectField(*defenderData, JavaLibrary::getFidCombatEngineDefenderDataHitLocationChances(), *chances);
// set the rest of the defender data
setObjectField(*defenderData, JavaLibrary::getFidCombatEngineCombatantDataPos(), *location);
setObjectField(*defenderData, JavaLibrary::getFidCombatEngineCombatantDataWorldPos(), *worldLocation);
setFloatField(*defenderData, JavaLibrary::getFidCombatEngineCombatantDataRadius(), defender->getRadius());
setBooleanField(*defenderData, JavaLibrary::getFidCombatEngineCombatantDataIsCreature(), isCreature);
setIntField(*defenderData, JavaLibrary::getFidCombatEngineCombatantDataPosture(), posture);
setIntField(*defenderData, JavaLibrary::getFidCombatEngineCombatantDataLocomotion(), locomotion);
setIntField(*defenderData, JavaLibrary::getFidCombatEngineCombatantDataScriptMod(), 0);
setIntField(*defenderData, JavaLibrary::getFidCombatEngineDefenderDataCombatSkeleton(), combatSkeleton);
setIntField(*defenderData, JavaLibrary::getFidCombatEngineDefenderDataCover(), cover);
}
return JNI_TRUE;
} // JavaLibrary::getCombatData
// ------------------------------------------------------------------------------------
/**
* Gets data needed for combat for a given weapon.
*
* @param env Java environment
* @param self class calling this function
* @param weapon the weapon to get data for
* @param weaponData data for the weapon
*
* @return JNI_TRUE on success, JNI_FALSE on error
*/
jboolean JNICALL ScriptMethodsCombatNamespace::getWeaponData(JNIEnv *env, jobject self, jlong weapon, jobject weaponData)
{
UNREF(self);
if (weapon == 0 || weaponData == 0)
return JNI_FALSE;
const WeaponObject * localWeapon = NULL;
if (!JavaLibrary::getObject(weapon, localWeapon))
return JNI_FALSE;
JavaLibrary::setupWeaponCombatData(env, localWeapon, weaponData);
return JNI_TRUE;
} // JavaLibrary::getWeaponData
// ------------------------------------------------------------------------------------
/**
* Applies damage to an object being attacked.
*
* @param env Java environment
* @param self class calling this function
* @param attackerId the attacker
* @param defenderId the defender
* @param weaponId the attacker's weapon
* @param damage amount of damage done
* @param hitLocation where the defender was hit
*
* @return JNI_TRUE on success, JNI_FALSE on error
*/
jboolean JNICALL ScriptMethodsCombatNamespace::doDamage(JNIEnv *env, jobject self, jlong attackerId, jlong defenderId, jlong weaponId, jint damage, jint hitLocation)
{
UNREF(self);
if (damage <= 0)
return JNI_TRUE;
TangibleObject * attacker = NULL;
if (!JavaLibrary::getObject(attackerId, attacker))
return JNI_FALSE;
TangibleObject * defender = NULL;
if (!JavaLibrary::getObject(defenderId, defender))
return JNI_FALSE;
WeaponObject * weapon = NULL;
if (!JavaLibrary::getObject(weaponId, weapon))
return JNI_FALSE;
bool result = CombatEngine::onSuccessfulAttack(*attacker, *defender, *weapon,
damage, hitLocation);
if (result)
return JNI_TRUE;
return JNI_FALSE;
} // JavaLibrary::doDamage
// ------------------------------------------------------------------------------------
/**
* Applies damage to an object being attacked.
*
* @param env Java environment
* @param self class calling this function
* @param attackerId the attacker
* @param defenderId the defender
* @param damage amount of damage done
* @param hitLocation where the defender was hit
*
* @return JNI_TRUE on success, JNI_FALSE on error
*/
jboolean JNICALL ScriptMethodsCombatNamespace::doDamageNoWeapon(JNIEnv *env, jobject self, jlong attackerId, jlong defenderId, jint damage, jint hitLocation)
{
UNREF(self);
if (damage <= 0)
return JNI_TRUE;
TangibleObject * attacker = NULL;
if (!JavaLibrary::getObject(attackerId, attacker))
return JNI_FALSE;
TangibleObject * defender = NULL;
if (!JavaLibrary::getObject(defenderId, defender))
return JNI_FALSE;
bool result = CombatEngine::onSuccessfulAttack(*attacker, *defender, damage, hitLocation);
if (result)
return JNI_TRUE;
return JNI_FALSE;
} // JavaLibrary::doDamage
// ------------------------------------------------------------------------------------
/**
* Creates a package to be sent to the client for displaying combat results.
*
* @param env Java environment
* @param self class calling this function
* @param animationId name of animation script to play
* @param attackerResult info about the attacker
* @param defenderResult info about the defender(s)
*
* @return JNI_TRUE on success, JNI_FALSE on error
*/
jboolean JNICALL ScriptMethodsCombatNamespace::doCombatResults(JNIEnv *env, jobject self,
jstring animationId, jobject attackerResult, jobjectArray defenderResult)
{
UNREF(self);
if (animationId == 0 || attackerResult == 0)
return JNI_FALSE;
JavaStringParam animationIdString(animationId);
std::string animationString;
if (!JavaLibrary::convert(animationIdString, animationString))
return JNI_FALSE;
unsigned int replaceWildcardIndex = animationString.find('^');
if( replaceWildcardIndex != std::string::npos)
{
std::string newString = animationString.substr(0, replaceWildcardIndex);
newString += s_wildcardReplacements[Random::random(0, totalWildcards-1)];
animationString = newString;
}
if (!ClientCombatManagerSupport::doesCombatActionNameExist(TemporaryCrcString(animationString.c_str(), true)))
{
WARNING(true, ("doCombatResults(): caller passed in unsupported combat action name [%s]! Continuing to send combat action. Call stack follows in stdout.", animationString.c_str()));
// @todo make this go to the log rather than stdout; otherwise, we're going to have to do a lot more work to see this info.
JavaLibrary::printJavaStack();
}
// create a CombatAction message and fill it in
MessageQueueCombatAction * message = new MessageQueueCombatAction();
message->setActionId(animationString);
// @todo: change set postures to set locomotions
// set attacker data
LocalRefPtr attackerId = getObjectField(LocalRefParam(attackerResult), JavaLibrary::getFidBaseClassAttackerResultsId());
CachedNetworkId attacker(JavaLibrary::getNetworkId(*attackerId));
LocalRefPtr weaponId = getObjectField(LocalRefParam(attackerResult), JavaLibrary::getFidBaseClassAttackerResultsWeapon());
CachedNetworkId weapon(JavaLibrary::getNetworkId(*weaponId));
if (attacker != CachedNetworkId::cms_invalid && attacker.getObject())
{
message->setAttacker(attacker, weapon);
CreatureObject * creature = dynamic_cast<CreatureObject *>(attacker.getObject());
if (creature != NULL)
{
Postures::Enumerator posture = static_cast<Postures::Enumerator>(
env->GetIntField(attackerResult, JavaLibrary::getFidBaseClassAttackerResultsPosture()));
if (posture >= 0 && posture < Postures::NumberOfPostures)
{
if (!creature->isIncapacitated())
creature->setPosture(posture);
else
posture = creature->getPosture();
}
else
{
WARNING(true, ("JavaLibrary::doCombatResults called with an invalid "
"posture %d for attacker %s", posture, attacker.getValueString().c_str()));
}
}
// Set the client trails special effects bitfield.
message->setAttackerTrailBits(env->GetIntField(attackerResult,
JavaLibrary::getFidBaseClassAttackerResultsTrailBits()));
// Set the attacker client effect id.
message->setAttackerClientEffectId(env->GetIntField(attackerResult,
JavaLibrary::getFidBaseClassAttackerResultsClientEffectId()));
// Set the attacker action name
message->setAttackerActionNameCrc(env->GetIntField(attackerResult,
JavaLibrary::getFidBaseClassAttackerResultsActionName()));
// Get the attacker useLocation field
bool useLocation = env->GetBooleanField(attackerResult,
JavaLibrary::getFidBaseClassAttackerResultsUseLocation());
Vector targetLocation;
if(useLocation)
{
LocalRefPtr targetLocationRef = getObjectField(LocalRefParam(attackerResult), JavaLibrary::getFidBaseClassAttackerResultsTargetLocation());
if (!ScriptConversion::convert((*targetLocationRef).getValue(), targetLocation))
JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::doCombatResults bad location target"));
LocalRefPtr targetCellRef = getObjectField(LocalRefParam(attackerResult), JavaLibrary::getFidBaseClassAttackerResultsTargetCell());
CachedNetworkId targetCell(JavaLibrary::getNetworkId(*targetCellRef));
message->setAttackerTargetLocation(targetLocation, targetCell, useLocation);
}
else
{
message->setAttackerTargetLocation(targetLocation, NetworkId::cms_invalid, useLocation);
}
}
else
{
JavaLibrary::throwInternalScriptError("JavaLibrary::doCombatResult() was passed an invalid attacker (not found on server)");
WARNING(true, ("JavaLibrary::doCombatResources called with invalid attacker %s",attacker.getValueString().c_str()));
delete message;
return JNI_FALSE;
}
// set defender(s) data
jsize defenderCount = 0;
if (defenderResult != 0)
defenderCount = env->GetArrayLength(defenderResult);
for (jsize i = 0; i < defenderCount; ++i)
{
LocalRefPtr defenderData = getObjectArrayElement(LocalObjectArrayRefParam(defenderResult), i);
if (defenderData != LocalRef::cms_nullPtr)
{
LocalRefPtr defenderId = getObjectField(*defenderData, JavaLibrary::getFidBaseClassDefenderResultsId());
CachedNetworkId defender(JavaLibrary::getNetworkId(*defenderId));
CombatEngineData::CombatDefense combatResult =
static_cast<CombatEngineData::CombatDefense>(
getIntField(*defenderData,
JavaLibrary::getFidBaseClassDefenderResultsResult()));
if (combatResult >= CombatEngineData::CD_numCombatDefense)
{
WARNING(true, ("doCombatResults(): caller passed in an invalid defender result [%d]! Setting result to COMBAT_RESULT_MISS. Call stack follows in stdout.", combatResult));
combatResult = CombatEngineData::CD_miss;
// @todo make this go to the log rather than stdout; otherwise, we're going to have to do a lot more work to see this info.
JavaLibrary::printJavaStack();
}
const int defenderClientEffectId = getIntField(*defenderData,
JavaLibrary::getFidBaseClassDefenderResultsClientEffectId());
Postures::Enumerator endPosture = static_cast<Postures::Enumerator>(
getIntField(*defenderData, JavaLibrary::getFidBaseClassDefenderResultsPosture()));
const int defenderHitLocation = getIntField(*defenderData,
JavaLibrary::getFidBaseClassDefenderResultsHitLocation());
CreatureObject * creature = dynamic_cast<CreatureObject *>(
defender.getObject());
if (creature)
{
if (endPosture >= 0 && endPosture < Postures::NumberOfPostures)
{
if (!creature->isIncapacitated())
creature->setPosture(endPosture);
else
endPosture = creature->getPosture();
}
else
{
WARNING(true, ("JavaLibrary::doCombatResults called with an "
"invalid posture %d for defender %s", endPosture,
defender.getValueString().c_str()));
}
}
const int defenderDamageAmount = getIntField(*defenderData,
JavaLibrary::getFidBaseClassDefenderDamageAmount());
message->addDefender(defender, combatResult, endPosture,
defenderClientEffectId, defenderHitLocation, defenderDamageAmount);
}
}
// send the message
Controller *const controller = attacker.getObject()->getController();
if (controller != NULL)
{
float f_hold_ms = ConfigServerGame::getCombatDamageDelaySeconds() * 1000.0f;
if ( f_hold_ms < 1.0 ) // 0 hold time (allowing for rounding error)
{
controller->appendMessage(
CM_combatAction,
0.0f,
message,
GameControllerMessageFlags::SEND |
GameControllerMessageFlags::RELIABLE |
GameControllerMessageFlags::DEST_ALL_CLIENT
);
}
else
{
MessageQueueCombatAction *held = (MessageQueueCombatAction*)controller->peekHeldMessage( CM_combatAction );
bool b_merge = true;
if ( held == NULL )
b_merge = false;
else if ( held->getComparisonChecksum() != message->getComparisonChecksum() )
b_merge = false;
if ( b_merge == false ) // can't merge, so hold for later sending
{
controller->holdMessage( int(f_hold_ms), CM_combatAction, 0.0f, message,
GameControllerMessageFlags::SEND |
GameControllerMessageFlags::RELIABLE |
GameControllerMessageFlags::DEST_ALL_CLIENT
);
}
else // do the merge
{
held->mergePacket( message );
delete( message );
}
}
}
else
{
delete message;
return JNI_FALSE;
}
return JNI_TRUE;
} // JavaLibrary::doCombatResults
// ------------------------------------------------------------------------------------
/**
* Triggers OnDefenderCombatAction for a list of defenders.
*
* @param env Java environment
* @param self class calling this function
* @param defenders list of defenders to be triggered
* @param results list of combat results for each defender
* @param attacker the attacker
* @param weapon the attacker's weapon
*
* @return JNI_TRUE on success, JNI_FALSE on error
*/
jboolean JNICALL ScriptMethodsCombatNamespace::callDefenderCombatAction(JNIEnv *env, jobject self, jlongArray defenders, jintArray results, jlong attacker, jlong weapon)
{
UNREF(self);
if (defenders == 0 || results == 0 || attacker == 0)
return JNI_FALSE;
jsize defenderCount = env->GetArrayLength(defenders);
jsize resultCount = env->GetArrayLength(results);
if (defenderCount != resultCount)
return JNI_FALSE;
// get the attacker info
CachedNetworkId attackerId(attacker);
NetworkId weaponId;
if (weapon != 0)
{
weaponId = NetworkId(weapon);
}
else
{
// use the attacker's current weapon
CreatureObject * creatureAttacker = dynamic_cast<CreatureObject *>(attackerId.getObject());
if (creatureAttacker != NULL)
{
const WeaponObject * weaponObject = creatureAttacker->getCurrentWeapon();
if (weaponObject != NULL)
weaponId = weaponObject->getNetworkId();
}
else
{
const WeaponObject * weaponAttacker = dynamic_cast<const WeaponObject *>(
attackerId.getObject());
if (weaponAttacker != NULL)
weaponId = weaponAttacker->getNetworkId();
}
}
// call the trigger for each defender
jint * resultsArray = env->GetIntArrayElements(results, NULL);
if (resultsArray == NULL)
return JNI_FALSE;
for (jsize i = 0; i < defenderCount; ++i)
{
jlong defender;
env->GetLongArrayRegion(defenders, i, 1, &defender);
if (defender)
{
CachedNetworkId defenderId(defender);
if (defenderId.getObject() != NULL)
{
ServerObject * defenderObject = safe_cast<ServerObject *>(
defenderId.getObject());
if (defenderObject->getScriptObject() != NULL)
{
ScriptParams params;
params.addParam(attackerId);
params.addParam(weaponId);
params.addParam(static_cast<int>(resultsArray[i]));
defenderObject->getScriptObject()->trigAllScripts(
Scripting::TRIG_DEFENDER_COMBAT_ACTION, params);
}
}
}
}
env->ReleaseIntArrayElements(results, resultsArray, JNI_ABORT);
return JNI_TRUE;
} // JavaLibrary::callDefenderCombatAction
// ------------------------------------------------------------------------------------
/**
* sets whether an object is interested in OnSawAttack triggers
*
* @param env Java environment
* @param self class calling this function
* @param obj the object in question
* @param enable whether OnSawAttack triggers should be enabled for the object
*/
void JNICALL ScriptMethodsCombatNamespace::setWantSawAttackTriggers(JNIEnv *env, jobject self, jlong obj, jboolean enable)
{
TangibleObject * tangible = NULL;
if (!JavaLibrary::getObject(obj, tangible))
{
JavaLibrary::throwInternalScriptError("JavaLibrary::setWantSawAttackTriggers - invalid object");
}
else
{
tangible->setWantSawAttackTriggers(enable == JNI_TRUE);
LOGC(AiLogManager::isLogging(tangible->getNetworkId()), "debug_ai", ("ScriptMethodsCombat::setWantSawAttackTriggers() object(%s) enable(%s)", tangible->getDebugInformation().c_str(), enable ? "yes" : "no"));
}
}
// ------------------------------------------------------------------------------------
/**
* Creates a "slow down" effect between an attacker and defender. The effect acts as if
* there was a hill between the combatants, with the attacker at the top and the defender
* at the bottom. The area of the effect is a cone between the attacker and defender.
* The "hill" will be maintained between the combatants even if they move.
*
* @param env Java environment
* @param self class calling this function
* @param attacker who is at the top of the hill
* @param defender who is at the bottom of the hill
* @param coneLength the length of the effect cone
* @param coneAngle the angle of the effect cone, in degrees; 0 < angle <= 180
* @param slopeAngle the effective angle of the slope in degrees; 1 <= slope < 90
* @param effectTime how long the effect will last, in secs
*
* @return true on success, false on fail
*/
jboolean JNICALL ScriptMethodsCombatNamespace::addSlowDownEffect(JNIEnv *env, jobject self, jlong attacker, jlong defender, jfloat coneLength, jfloat coneAngle, jfloat slopeAngle, jfloat effectTime)
{
if (coneLength <= 0)
{
WARNING(true, ("[script bug] JavaLibrary::addSlowDownEffect called "
"with invalid cone length %f", coneLength));
return JNI_FALSE;
}
if (coneAngle <= 0 || coneAngle > 180)
{
WARNING(true, ("[script bug] JavaLibrary::addSlowDownEffect called "
"with invalid cone angle %f", coneAngle));
return JNI_FALSE;
}
if (slopeAngle < 1 || slopeAngle >= 90)
{
WARNING(true, ("[script bug] JavaLibrary::addSlowDownEffect called "
"with invalid slope angle %f", slopeAngle));
return JNI_FALSE;
}
if (effectTime <= 0)
{
WARNING(true, ("[script bug] JavaLibrary::addSlowDownEffect called "
"with invalid time %f", effectTime));
return JNI_FALSE;
}
CreatureObject * attackerObject = NULL;
if (!JavaLibrary::getObject(attacker, attackerObject))
{
WARNING(true, ("[script bug] JavaLibrary::addSlowDownEffect called "
"with invalid attacker"));
return JNI_FALSE;
}
const TangibleObject * defenderObject = NULL;
if (!JavaLibrary::getObject(defender, defenderObject))
{
WARNING(true, ("[script bug] JavaLibrary::addSlowDownEffect called "
"with invalid defender"));
return JNI_FALSE;
}
unsigned long expireTime = static_cast<unsigned long>(effectTime) + ServerClock::getInstance().getGameTimeSeconds();
attackerObject->addSlowDownEffect(*defenderObject, coneLength,
convertDegreesToRadians(coneAngle), convertDegreesToRadians(slopeAngle),
expireTime);
return JNI_TRUE;
} // JavaLibrary::addSlowDownEffect
// ------------------------------------------------------------------------------------
/**
* Causes a slow down effect being used by an attacker to be canceled early.
*
* @param env Java environment
* @param self class calling this function
* @param attacker the attacker who is using the effect
*
* @return true on success, false on error (bad attacker)
*/
jboolean JNICALL ScriptMethodsCombatNamespace::removeSlowDownEffect(JNIEnv *env, jobject self, jlong attacker)
{
CreatureObject * attackerObject = NULL;
if (!JavaLibrary::getObject(attacker, attackerObject))
{
WARNING(true, ("[script bug] JavaLibrary::removeSlowDownEffect called "
"with invalid attacker"));
return JNI_FALSE;
}
attackerObject->removeSlowDownEffect();
return JNI_TRUE;
} // JavaLibrary::removeSlowDownEffect
// ------------------------------------------------------------------------------------
/**
* Sends standard combat spam info to players.
*
* @param env Java environment
* @param self class calling this function
* @param attacker who the attacker was
* @param defender who the defender was
* @param weapon what weapon was used
* @param result structure with the numerical data for the attack
* @param attackName the name of the attack
* @param sendToAttacker flag to send the spam to the attacker
* @param sendToDefender flag to send the spam to the defender
* @param sendToBystanders flag to send the spam to other players near the combat
* @param spamType flag that sets what color the spam will be show as
*/
void JNICALL ScriptMethodsCombatNamespace::sendCombatSpam(JNIEnv *env, jobject self, jlong attacker, jlong defender, jlong weapon, jobject result, jobject attackName, jboolean sendToAttacker, jboolean sendToDefender, jboolean sendToBystanders, jint spamType)
{
NetworkId attackerId(attacker);
ServerObject * attackerObj = safe_cast<ServerObject *>(NetworkIdManager::getObjectById(attackerId));
if (attackerObj == NULL)
{
WARNING(true, ("WARNING: JavaLibrary::sendCombatSpam could not find attacker for id %s", attackerId.getValueString().c_str()));
return;
}
NetworkId defenderId(defender);
Object const * const defenderObj = (defenderId.isValid() ? NetworkIdManager::getObjectById(defenderId) : NULL);
NetworkId weaponId(weapon);
StringId attackNameSid;
if (!ScriptConversion::convert(attackName, attackNameSid))
return;
int rawDamage = 0;
int damageType = 0;
int elementalDamage = 0;
int elementalDamageType = 0;
int bleedDamage = 0;
int critDamage = 0;
int blockedDamage = 0;
int finalDamage = 0;
int hitLocation = 0;
jboolean success = false;
jboolean critical = false;
jboolean glancing = false;
jboolean crushing = false;
jboolean strikethrough = false;
float strikethroughAmmount = 0.0f;
jboolean evadeResult = false;
float evadeAmmount = 0.0f;
jboolean blockResult = false;
int block = 0;
jboolean dodge = false;
jboolean parry = false;
jboolean proc = false;
NetworkId armorId;
if (result != 0)
{
LocalRefParam jresult(result);
success = getBooleanField(jresult, JavaLibrary::getFidCombatEngineHitResultSuccess());
critical = getBooleanField(jresult, JavaLibrary::getFidCombatEngineHitResultCritical());
glancing = getBooleanField(jresult, JavaLibrary::getFidCombatEngineHitResultGlancing());
proc = getBooleanField(jresult, JavaLibrary::getFidCombatEngineHitResultProc());
if (success)
{
LocalRefPtr armor = getObjectField(jresult, JavaLibrary::getFidCombatEngineHitResultBlockingArmor());
armorId = JavaLibrary::getNetworkId(*armor);
rawDamage = getIntField(jresult, JavaLibrary::getFidCombatEngineHitResultRawDamage());
damageType = getIntField(jresult, JavaLibrary::getFidCombatEngineHitResultDamageType());
elementalDamage = getIntField(jresult, JavaLibrary::getFidCombatEngineHitResultElementalDamage());
elementalDamageType = getIntField(jresult, JavaLibrary::getFidCombatEngineHitResultElementalDamageType());
bleedDamage = getIntField(jresult, JavaLibrary::getFidCombatEngineHitResultBleedDamage());
critDamage = getIntField(jresult, JavaLibrary::getFidCombatEngineHitResultCritDamage());
blockedDamage = getIntField(jresult, JavaLibrary::getFidCombatEngineHitResultBlockedDamage());
finalDamage = getIntField(jresult, JavaLibrary::getFidCombatEngineHitResultDamage());
hitLocation = getIntField(jresult, JavaLibrary::getFidCombatEngineHitResultHitLocation());
crushing = getBooleanField(jresult, JavaLibrary::getFidCombatEngineHitResultCrushing());
strikethrough = getBooleanField(jresult, JavaLibrary::getFidCombatEngineHitResultStrikethrough());
strikethroughAmmount = getFloatField(jresult, JavaLibrary::getFidCombatEngineHitResultStrikethroughAmount());
evadeResult = getBooleanField(jresult, JavaLibrary::getFidCombatEngineHitResultEvadeResult());
evadeAmmount = getFloatField(jresult, JavaLibrary::getFidCombatEngineHitResultEvadeAmount());
blockResult = getBooleanField(jresult, JavaLibrary::getFidCombatEngineHitResultBlockResult());
block = getIntField(jresult, JavaLibrary::getFidCombatEngineHitResultBlock());
}
else
{
dodge = getBooleanField(jresult, JavaLibrary::getFidCombatEngineHitResultDodge());
parry = getBooleanField(jresult, JavaLibrary::getFidCombatEngineHitResultParry());
}
}
MessageQueueCombatSpam spam(attackerId, attackerObj->getPosition_w(), defenderId, (defenderObj ? defenderObj->getPosition_w() : Vector::zero), weaponId, armorId, attackNameSid, rawDamage, damageType, elementalDamage, elementalDamageType, bleedDamage, critDamage, blockedDamage, finalDamage, hitLocation, success, critical, glancing, crushing, strikethrough, strikethroughAmmount, evadeResult, evadeAmmount, blockResult, block, dodge, parry, proc, spamType);
attackerObj->performCombatSpam(spam, sendToAttacker, sendToDefender, sendToBystanders);
} // JavaLibrary::sendCombatSpam
/**
* Sends standard combat spam info to players. The weapon is a string id instead
* of an object.
*
* @param env Java environment
* @param self class calling this function
* @param attacker who the attacker was
* @param defender who the defender was
* @param weaponName the name of the weapon used
* @param result structure with the numerical data for the attack
* @param attackName the name of the attack
* @param sendToAttacker flag to send the spam to the attacker
* @param sendToDefender flag to send the spam to the defender
* @param sendToBystanders flag to send the spam to other players near the combat
* @param spamType flag that sets what color the spam will be show as
*/
void JNICALL ScriptMethodsCombatNamespace::sendCombatSpamWeaponString(JNIEnv *env, jobject self, jlong attacker, jlong defender, jobject weaponName, jobject result, jobject attackName, jboolean sendToAttacker, jboolean sendToDefender, jboolean sendToBystanders, jint spamType)
{
NetworkId attackerId(attacker);
ServerObject * attackerObj = safe_cast<ServerObject *>(NetworkIdManager::getObjectById(attackerId));
if (attackerObj == NULL)
{
WARNING(true, ("WARNING: JavaLibrary::sendCombatSpam could not find attacker for id %s", attackerId.getValueString().c_str()));
return;
}
NetworkId defenderId(defender);
Object const * const defenderObj = (defenderId.isValid() ? NetworkIdManager::getObjectById(defenderId) : NULL);
StringId weaponNameSid;
if (!ScriptConversion::convert(weaponName, weaponNameSid))
return;
StringId attackNameSid;
if (!ScriptConversion::convert(attackName, attackNameSid))
return;
int rawDamage = 0;
int damageType = 0;
int elementalDamage = 0;
int elementalDamageType = 0;
int bleedDamage = 0;
int critDamage = 0;
int blockedDamage = 0;
int finalDamage = 0;
int hitLocation = 0;
jboolean success = false;
jboolean critical = false;
jboolean glancing = false;
jboolean crushing = false;
jboolean strikethrough = false;
float strikethroughAmmount = 0.0f;
jboolean evadeResult = false;
float evadeAmmount = 0.0f;
jboolean blockResult = false;
int block = 0;
jboolean dodge = false;
jboolean parry = false;
jboolean proc = false;
NetworkId armorId;
if (result != 0)
{
LocalRefParam jresult(result);
success = getBooleanField(jresult, JavaLibrary::getFidCombatEngineHitResultSuccess());
critical = getBooleanField(jresult, JavaLibrary::getFidCombatEngineHitResultCritical());
glancing = getBooleanField(jresult, JavaLibrary::getFidCombatEngineHitResultGlancing());
proc = getBooleanField(jresult, JavaLibrary::getFidCombatEngineHitResultProc());
if (success)
{
LocalRefPtr armor = getObjectField(jresult, JavaLibrary::getFidCombatEngineHitResultBlockingArmor());
armorId = JavaLibrary::getNetworkId(*armor);
rawDamage = getIntField(jresult, JavaLibrary::getFidCombatEngineHitResultRawDamage());
damageType = getIntField(jresult, JavaLibrary::getFidCombatEngineHitResultDamageType());
elementalDamage = getIntField(jresult, JavaLibrary::getFidCombatEngineHitResultElementalDamage());
elementalDamageType = getIntField(jresult, JavaLibrary::getFidCombatEngineHitResultElementalDamageType());
bleedDamage = getIntField(jresult, JavaLibrary::getFidCombatEngineHitResultBleedDamage());
critDamage = getIntField(jresult, JavaLibrary::getFidCombatEngineHitResultCritDamage());
blockedDamage = getIntField(jresult, JavaLibrary::getFidCombatEngineHitResultBlockedDamage());
finalDamage = getIntField(jresult, JavaLibrary::getFidCombatEngineHitResultDamage());
hitLocation = getIntField(jresult, JavaLibrary::getFidCombatEngineHitResultHitLocation());
crushing = getBooleanField(jresult, JavaLibrary::getFidCombatEngineHitResultCrushing());
strikethrough = getBooleanField(jresult, JavaLibrary::getFidCombatEngineHitResultStrikethrough());
strikethroughAmmount = getFloatField(jresult, JavaLibrary::getFidCombatEngineHitResultStrikethroughAmount());
evadeResult = getBooleanField(jresult, JavaLibrary::getFidCombatEngineHitResultEvadeResult());
evadeAmmount = getFloatField(jresult, JavaLibrary::getFidCombatEngineHitResultEvadeAmount());
blockResult = getBooleanField(jresult, JavaLibrary::getFidCombatEngineHitResultBlockResult());
block = getIntField(jresult, JavaLibrary::getFidCombatEngineHitResultBlock());
}
else
{
dodge = getBooleanField(jresult, JavaLibrary::getFidCombatEngineHitResultDodge());
parry = getBooleanField(jresult, JavaLibrary::getFidCombatEngineHitResultParry());
}
}
MessageQueueCombatSpam spam(attackerId, attackerObj->getPosition_w(), defenderId, (defenderObj ? defenderObj->getPosition_w() : Vector::zero), weaponNameSid, armorId, attackNameSid, rawDamage, damageType, elementalDamage, elementalDamageType, bleedDamage, critDamage, blockedDamage, finalDamage, hitLocation, success, critical, glancing, crushing, strikethrough, strikethroughAmmount, evadeResult, evadeAmmount, blockResult, block, dodge, parry, proc, spamType);
attackerObj->performCombatSpam(spam, sendToAttacker, sendToDefender, sendToBystanders);
} // JavaLibrary::sendCombatSpamWeaponString
// ------------------------------------------------------------------------------------
/**
* Send a string id to a player in the combat spam window.
*
* @param env Java environment
* @param self class calling this function
* @param attacker the main player associated with the spam
* @param defender who the attacker is interacting with
* @param message the message
* @param sendToAttacker flag to send the message to the attacker
* @param sendToDefender flag to send the message to the defender
* @param sendToBystanders flag to send the message to anyone else in the area
* @param spamType flag that sets what color the spam will be show as
*/
void JNICALL ScriptMethodsCombatNamespace::sendCombatSpamMessage(JNIEnv *env, jobject self, jlong attacker, jlong defender, jobject message, jboolean sendToAttacker, jboolean sendToDefender, jboolean sendToBystanders, jint spamType)
{
ServerObject * attackerObj = NULL;
if (!JavaLibrary::getObject(attacker, attackerObj))
return;
NetworkId defenderId(defender);
Object const * const defenderObj = (defenderId.isValid() ? NetworkIdManager::getObjectById(defenderId) : NULL);
StringId messageSid;
if (!ScriptConversion::convert(message, messageSid))
return;
MessageQueueCombatSpam spam(attackerObj->getNetworkId(), attackerObj->getPosition_w(), defenderId, (defenderObj ? defenderObj->getPosition_w() : Vector::zero), Unicode::narrowToWide("@" + messageSid.getCanonicalRepresentation()), false, false, false, spamType);
attackerObj->performCombatSpam(spam, sendToAttacker, sendToDefender, sendToBystanders);
} // JavaLibrary::sendCombatSpamMessage
// ------------------------------------------------------------------------------------
/**
* Send a string id to a player in the combat spam window.
*
* @param env Java environment
* @param self class calling this function
* @param attacker the main player associated with the spam
* @param defender who the attacker is interacting with
* @param message the message
* @param sendToAttacker flag to send the message to the attacker
* @param sendToDefender flag to send the message to the defender
* @param sendToBystanders flag to send the message to anyone else in the area
* @param critical changes spam on client
* @param glancing changes spam on client
* @param proc changes spam on client
* @param spamType flag that sets what color the spam will be show as
*/
void JNICALL ScriptMethodsCombatNamespace::sendCombatSpamMessageCGP(JNIEnv *env, jobject self, jlong attacker, jlong defender, jobject message, jboolean sendToAttacker, jboolean sendToDefender, jboolean sendToBystanders, jboolean critical, jboolean glancing, jboolean proc, jint spamType)
{
ServerObject * attackerObj = NULL;
if (!JavaLibrary::getObject(attacker, attackerObj))
return;
NetworkId defenderId(defender);
Object const * const defenderObj = (defenderId.isValid() ? NetworkIdManager::getObjectById(defenderId) : NULL);
StringId messageSid;
if (!ScriptConversion::convert(message, messageSid))
return;
MessageQueueCombatSpam spam(attackerObj->getNetworkId(), attackerObj->getPosition_w(), defenderId, (defenderObj ? defenderObj->getPosition_w() : Vector::zero), Unicode::narrowToWide("@" + messageSid.getCanonicalRepresentation()), critical, glancing, proc, spamType);
attackerObj->performCombatSpam(spam, sendToAttacker, sendToDefender, sendToBystanders);
} // JavaLibrary::sendCombatSpamMessage
// ------------------------------------------------------------------------------------
/**
* Send an out-of-band package to a player in the combat spam window.
*
* @param env Java environment
* @param self class calling this function
* @param attacker the main player associated with the spam
* @param defender who the attacker is interacting with
* @param message the message
* @param sendToAttacker flag to send the message to the attacker
* @param sendToDefender flag to send the message to the defender
* @param sendToBystanders flag to send the message to anyone else in the area
* @param spamType flag that sets what color the spam will be show as
*/
void JNICALL ScriptMethodsCombatNamespace::sendCombatSpamMessageOob(JNIEnv *env, jobject self, jlong attacker, jlong defender, jstring oob, jboolean sendToAttacker, jboolean sendToDefender, jboolean sendToBystanders, jint spamType)
{
ServerObject * attackerObj = NULL;
if (!JavaLibrary::getObject(attacker, attackerObj))
return;
NetworkId defenderId(defender);
Object const * const defenderObj = (defenderId.isValid() ? NetworkIdManager::getObjectById(defenderId) : NULL);
Unicode::String oobString;
if (!JavaLibrary::convert(JavaStringParam(oob), oobString))
return;
MessageQueueCombatSpam spam(attackerObj->getNetworkId(), attackerObj->getPosition_w(), defenderId, (defenderObj ? defenderObj->getPosition_w() : Vector::zero), oobString, false, false, false, spamType);
attackerObj->performCombatSpam(spam, sendToAttacker, sendToDefender, sendToBystanders);
} // JavaLibrary::sendCombatSpamMessageOob
// ------------------------------------------------------------------------------------
void JNICALL ScriptMethodsCombatNamespace::incrementKillMeter(JNIEnv *env, jobject self, jlong player, jint amount )
{
CreatureObject* playerCreature = 0;
if (!JavaLibrary::getObject(player, playerCreature))
return;
if (!playerCreature->isPlayerControlled())
return;
PlayerObject* playerObject = PlayerCreatureController::getPlayerObject(playerCreature);
if (!playerObject)
return;
playerObject->incrementKillMeter(amount);
}
// ------------------------------------------------------------------------------------
jint JNICALL ScriptMethodsCombatNamespace::getKillMeter(JNIEnv *env, jobject self, jlong player )
{
CreatureObject* playerCreature = 0;
if (!JavaLibrary::getObject(player, playerCreature))
return 0;
if (!playerCreature->isPlayerControlled())
return 0;
PlayerObject* playerObject = PlayerCreatureController::getPlayerObject(playerCreature);
if (!playerObject)
return 0;
return playerObject->getKillMeter();
}
// ------------------------------------------------------------------------------------
jboolean JNICALL ScriptMethodsCombatNamespace::overrideDefaultAttack(JNIEnv *env, jobject self, jlong player, jstring attack)
{
CreatureObject* playerCreature = 0;
if (!JavaLibrary::getObject(player, playerCreature))
return JNI_FALSE;
if (!playerCreature->isPlayerControlled())
return JNI_FALSE;
PlayerObject* playerObject = PlayerCreatureController::getPlayerObject(playerCreature);
if (!playerObject)
return JNI_FALSE;
JavaStringParam javaAttack(attack);
std::string convertAttack;
if (!JavaLibrary::convert(javaAttack, convertAttack))
return JNI_FALSE;
playerObject->overrideDefaultAttack(convertAttack);
return JNI_TRUE;
}
// ------------------------------------------------------------------------------------
jboolean JNICALL ScriptMethodsCombatNamespace::removeDefaultAttackOverride(JNIEnv *env, jobject self, jlong player)
{
CreatureObject* playerCreature = 0;
if (!JavaLibrary::getObject(player, playerCreature))
return JNI_FALSE;
if (!playerCreature->isPlayerControlled())
return JNI_FALSE;
PlayerObject* playerObject = PlayerCreatureController::getPlayerObject(playerCreature);
if (!playerObject)
return JNI_FALSE;
// Setting the attack override to an empty string removes the effect on the client.
playerObject->overrideDefaultAttack(std::string());
return JNI_TRUE;
}
// ------------------------------------------------------------------------------------
jstring JNICALL ScriptMethodsCombatNamespace::getDefaultAttackOverrideActionName(JNIEnv *env, jobject self, jlong player)
{
CreatureObject* playerCreature = 0;
if (!JavaLibrary::getObject(player, playerCreature))
return JNI_FALSE;
if (!playerCreature->isPlayerControlled())
return JNI_FALSE;
PlayerObject* playerObject = PlayerCreatureController::getPlayerObject(playerCreature);
if (!playerObject)
return JNI_FALSE;
return JavaString(playerObject->getDefaultAttackOverride()).getValue();
}
// ======================================================================