Initial Upload
Initial Upload
This commit is contained in:
484
_module/nss/ka_i_weapon.nss
Normal file
484
_module/nss/ka_i_weapon.nss
Normal file
@@ -0,0 +1,484 @@
|
||||
//::///////////////////////////////////////////////
|
||||
//:: ka_i_weapon.nss
|
||||
//:: Copyright (c) 2003 Karl Adamaitis
|
||||
//:://////////////////////////////////////////////
|
||||
/*
|
||||
common defines and functionality for placeable
|
||||
weapon objects.
|
||||
*/
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Created By: Karl Adamaitis
|
||||
//:: Created On: Aug 30, 2002
|
||||
//:://////////////////////////////////////////////
|
||||
//
|
||||
int StartingConditional()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// common range definitions
|
||||
//
|
||||
|
||||
int KA_MAX_WEAPON_RANGE = 280;
|
||||
|
||||
int KA_MIN_WEAPON_RANGE = 20;
|
||||
|
||||
float KA_WEAPON_BLAST_RADIUS = 12.0; // meters
|
||||
|
||||
// DAMAGE - amount of variable damage this placeable weapon inflicts.
|
||||
|
||||
int WEAPON_DAMAGE = d6(3) + 2;
|
||||
|
||||
|
||||
|
||||
//
|
||||
// prototypes
|
||||
//
|
||||
|
||||
|
||||
// move placeable weapon object forwards/backwards a distance
|
||||
void KaWeaponMove(object oOBJ, object oPC, int iDistMove);
|
||||
|
||||
// adjust placeable weapon object's range forwards/backwards a distance
|
||||
void KaWeaponRange(object oOBJ, object oPC, int iDistChangeRange);
|
||||
|
||||
// rotate placeable weapon object clockwise/counter-clockwise
|
||||
void KaWeaponRotate(object oOBJ, object oPC, float fDegrees);
|
||||
|
||||
// fire the placeable weapon. if a commander is given then the target is an enemy within the striking area of the catapult's projectile.
|
||||
void KaWeaponFire(object oOBJ, object oCommander = OBJECT_INVALID, object oTarget = OBJECT_INVALID, int iMaxVariation = 20);
|
||||
|
||||
|
||||
// separate function for area effect in order to properly
|
||||
// time the impact with the area-damage event.
|
||||
void KaPrivWeaponAreaEffect(location locImpact, float fRadius, effect eEffect);
|
||||
|
||||
// adjust the location within a variance of meters
|
||||
location KaPrivCreateLocationVariance(location loc, int iMeters);
|
||||
|
||||
// string table function
|
||||
string StringTable(int nStringRef, string sLCID = "en");
|
||||
|
||||
|
||||
|
||||
//
|
||||
// functions:
|
||||
//
|
||||
|
||||
|
||||
void KaWeaponMove(object oOBJ, object oPC, int iDistMove)
|
||||
{
|
||||
vector vecCurrentPosition = GetPosition(oOBJ);
|
||||
|
||||
float fCurrentFacing = GetFacing(oOBJ);
|
||||
|
||||
vector vecDifference;
|
||||
|
||||
// adjust the distance (positive or negative integer values)
|
||||
|
||||
vecDifference.x = iDistMove * cos(fCurrentFacing);
|
||||
|
||||
vecDifference.y = iDistMove * sin(fCurrentFacing);
|
||||
|
||||
vector vecNewPosition;
|
||||
|
||||
vecNewPosition.x = vecCurrentPosition.x + vecDifference.x;
|
||||
|
||||
vecNewPosition.y = vecCurrentPosition.y + vecDifference.y;
|
||||
|
||||
// create the new location (by definition; area, vector, and orientation).
|
||||
|
||||
location locNewPosition = Location(GetArea(oOBJ), vecNewPosition, fCurrentFacing);
|
||||
|
||||
// new position is calculated - get the tag for support of different weapon objects
|
||||
// NOTE: the tag string and blueprint resource string MUST be the same. use the
|
||||
// custom weapon objects created that have this condition set. otherwise, the
|
||||
// newly created object will be default without the resource definitions.
|
||||
|
||||
string stagBlueprintRes = GetTag(oOBJ);
|
||||
|
||||
// remove the current instance of weapon object and replace in new location
|
||||
|
||||
DestroyObject(oOBJ);
|
||||
|
||||
object oNewWeapon = CreateObject(
|
||||
OBJECT_TYPE_PLACEABLE,
|
||||
stagBlueprintRes,
|
||||
locNewPosition);
|
||||
|
||||
// relaunch the conversation file with PC/object for further command processing
|
||||
// NOTE: requires command conversation file (give recursive behaviour).
|
||||
|
||||
AssignCommand(oNewWeapon, ActionStartConversation(oPC, "", TRUE));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void KaWeaponRange(object oOBJ, object oPC, int iDistChangeRange)
|
||||
{
|
||||
// get the current range value
|
||||
|
||||
int iRange = GetLocalInt(oOBJ, "KA_WEAPON_RANGE");
|
||||
|
||||
// increment or decrement the range
|
||||
|
||||
iRange = iRange + iDistChangeRange;
|
||||
|
||||
// verify range of weapon is above minimum and below maximum allowed
|
||||
|
||||
if (KA_MIN_WEAPON_RANGE > iRange) {
|
||||
|
||||
// adjust the range to minimum distance
|
||||
|
||||
iRange = KA_MIN_WEAPON_RANGE; // meters
|
||||
|
||||
} else if (KA_MAX_WEAPON_RANGE < iRange) {
|
||||
|
||||
// adjust the range to maximum distance
|
||||
|
||||
iRange = KA_MAX_WEAPON_RANGE; // meters
|
||||
}
|
||||
|
||||
AssignCommand(oOBJ, ActionSpeakString(
|
||||
StringTable(0) + //"Range: "
|
||||
IntToString(iRange)
|
||||
));
|
||||
|
||||
// set the local integer value - referenced when weapon is discharged
|
||||
|
||||
AssignCommand(oOBJ, SetLocalInt(oOBJ, "KA_WEAPON_RANGE", iRange));
|
||||
|
||||
// relaunch the conversation file with PC/object for further command processing
|
||||
// NOTE: requires command conversation file (give recursive behaviour).
|
||||
|
||||
AssignCommand(oOBJ, ActionStartConversation(oPC, "", TRUE));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void KaWeaponRotate(object oOBJ, object oPC, float fDegrees)
|
||||
{
|
||||
float fCurrent = GetFacing(oOBJ);
|
||||
|
||||
float fNew = fCurrent - fDegrees; // add/remove degrees (i.e. clockwise/counter-clockwise)
|
||||
|
||||
if (fNew <= 0.0) {
|
||||
|
||||
// rotation has come about full-circle
|
||||
|
||||
fNew += 360.0;
|
||||
}
|
||||
|
||||
SetFacing(fNew);
|
||||
|
||||
// relaunch the conversation file with PC/object for further command processing
|
||||
// NOTE: requires command conversation file (give recursive behaviour).
|
||||
|
||||
AssignCommand(oOBJ, ActionStartConversation(oPC, "", TRUE));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void KaWeaponFire(
|
||||
object oOBJ,
|
||||
object oCommander, // OBJECT_INVALID
|
||||
object oTarget, // OBJECT_INVALID
|
||||
int iMaxVariation) // 20m
|
||||
{
|
||||
if (!GetIsObjectValid(oOBJ)) {
|
||||
WriteTimestampedLogEntry("KA_ERROR: KaWeaponFire - invalid object oOBJ");
|
||||
return; // error
|
||||
}
|
||||
|
||||
// verify that the maximum variation is valid
|
||||
|
||||
if (iMaxVariation <= 1) {
|
||||
|
||||
// too small, increase and log an error
|
||||
|
||||
iMaxVariation = 2;
|
||||
|
||||
WriteTimestampedLogEntry("KA_ERROR: KaWeaponFire - the maximum variation is too small, setting to minimum of: " + IntToString(iMaxVariation));
|
||||
}
|
||||
|
||||
// calculate the impact location based on orientation and range of weapon
|
||||
|
||||
float fCurrentFacing = GetFacing(oOBJ);
|
||||
|
||||
int iRange = GetLocalInt(oOBJ, "KA_WEAPON_RANGE");
|
||||
|
||||
if (KA_MIN_WEAPON_RANGE >= iRange) {
|
||||
|
||||
// adjust the range to minimum distance
|
||||
|
||||
iRange = KA_MIN_WEAPON_RANGE; // meters
|
||||
}
|
||||
|
||||
vector vecDelta;
|
||||
|
||||
vecDelta.x = iRange * cos(fCurrentFacing);
|
||||
|
||||
vecDelta.y = iRange * sin(fCurrentFacing);
|
||||
|
||||
vector vecImpact;
|
||||
|
||||
vector vecPosition = GetPosition(oOBJ);
|
||||
|
||||
vecImpact.x = vecPosition.x + vecDelta.x;
|
||||
|
||||
vecImpact.y = vecPosition.y + vecDelta.y;
|
||||
|
||||
// create the impact location from area
|
||||
|
||||
location locImpact = Location(GetArea(oOBJ), vecImpact, fCurrentFacing);
|
||||
|
||||
if (GetIsObjectValid(oTarget)) {
|
||||
|
||||
// variation for the impact location
|
||||
|
||||
vector vecTarget = GetPosition(oTarget);
|
||||
|
||||
int iXPosNeg = 1; // x coordinate positive/negative targeting adjustment
|
||||
|
||||
if (d2(1) == 1) {
|
||||
|
||||
iXPosNeg = -1; // random negative adjustment override
|
||||
}
|
||||
|
||||
int iYPosNeg = 1; // y coordinate positive/negative targeting adjustment
|
||||
|
||||
if (d2(1) == 1) {
|
||||
|
||||
iYPosNeg = -1; // random negative adjustment override
|
||||
}
|
||||
|
||||
// create the new target impact location randomizing x and y coordinates separately
|
||||
|
||||
vecTarget.x = vecTarget.x + (iXPosNeg * Random(iMaxVariation));
|
||||
|
||||
vecTarget.y = vecTarget.y + (iYPosNeg * Random(iMaxVariation));
|
||||
|
||||
// create the new location for the impact based on variation calculated above
|
||||
// NOTE: using target's area, vector for location and facing direction from weapon.
|
||||
|
||||
locImpact = Location(GetArea(oTarget), vecTarget, fCurrentFacing);
|
||||
}
|
||||
|
||||
// override the impact location if a commander is given and the catapult's commander
|
||||
// is enemies with an object within a location. used for PC's firing catapult to
|
||||
// support friendlies. this is performed by using the previously calculated location
|
||||
// of impact and finding the nearest enemy within range to the catapult's commander.
|
||||
|
||||
if (GetIsObjectValid(oCommander)) {
|
||||
|
||||
// NOTE: do not use GetNearestCreatureToLocation with REPUTATION as causes AV in
|
||||
// module on patch 1.29, nor does this make sense as the location does not provide
|
||||
// data member in struct that represents the reputation of commander.
|
||||
|
||||
int iCount = 1;
|
||||
|
||||
int iMaxCount = 4;
|
||||
|
||||
int b_enemy = FALSE; // TRUE to terminate search
|
||||
|
||||
object oEnemyFound = GetNearestCreatureToLocation(
|
||||
CREATURE_TYPE_IS_ALIVE,
|
||||
TRUE,
|
||||
locImpact,
|
||||
iCount
|
||||
);
|
||||
|
||||
while (GetIsObjectValid(oEnemyFound) && (iCount <= iMaxCount) && (FALSE == b_enemy)) {
|
||||
|
||||
// verify if this really is an enemy of the catapult's commander
|
||||
|
||||
b_enemy = GetIsEnemy(oEnemyFound, oCommander);
|
||||
|
||||
if (TRUE == b_enemy) {
|
||||
|
||||
// verify that the found enemy is within the maximum allowed range from impact location
|
||||
|
||||
location locEnemy = GetLocation(oEnemyFound);
|
||||
|
||||
float fDist = GetDistanceBetweenLocations(locImpact, locEnemy);
|
||||
|
||||
float fMaxVariation = IntToFloat(iMaxVariation);
|
||||
|
||||
if (fDist < fMaxVariation) {
|
||||
|
||||
// enemy is within maximum variation from impact location, override the impact location
|
||||
// with a new impact location that is close to the new target.
|
||||
|
||||
location locOrigImpact = locImpact;
|
||||
|
||||
locImpact = KaPrivCreateLocationVariance(
|
||||
locOrigImpact, // <-- original calculated impact location
|
||||
3 // <-- maximum variance from the new found enemy target within max variance of impact
|
||||
);
|
||||
|
||||
} else {
|
||||
|
||||
// no enemy was found that meets all conditions, leave the bool
|
||||
// to true to terminate the search and just fire the catapult.
|
||||
// the nearest enemy is outside of the maximum distance from the
|
||||
// impact location of the catapult as aimed by the catapult's
|
||||
// commander. the commander must re-aim the catapult.
|
||||
}
|
||||
}
|
||||
|
||||
// increment the count looking for another enemy
|
||||
|
||||
iCount++;
|
||||
|
||||
oEnemyFound = GetNearestCreatureToLocation(
|
||||
CREATURE_TYPE_IS_ALIVE,
|
||||
TRUE,
|
||||
locImpact,
|
||||
iCount
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
float fPauseBefore = 1.1;
|
||||
|
||||
AssignCommand(oOBJ, ClearAllActions());
|
||||
|
||||
AssignCommand(oOBJ, DelayCommand(fPauseBefore, ActionCastSpellAtLocation(
|
||||
SPELL_FIREBALL,
|
||||
locImpact,
|
||||
METAMAGIC_MAXIMIZE,
|
||||
TRUE,
|
||||
PROJECTILE_PATH_TYPE_BALLISTIC,
|
||||
TRUE)));
|
||||
|
||||
}
|
||||
|
||||
|
||||
location KaPrivCreateLocationVariance(location loc, int iMeters)
|
||||
{
|
||||
if (0 == iMeters) {
|
||||
// no variance
|
||||
return loc;
|
||||
}
|
||||
|
||||
// validate the location's area
|
||||
|
||||
if (!GetIsObjectValid(GetAreaFromLocation(loc))) {
|
||||
WriteTimestampedLogEntry("KA_ERROR: KaPrivCreateLocationVariance (ka_i_weapon) - invalid area object for location");
|
||||
return loc;
|
||||
}
|
||||
|
||||
vector vecPos = GetPositionFromLocation(loc);
|
||||
|
||||
object oArea = GetAreaFromLocation(loc);
|
||||
|
||||
// validate returned vector position
|
||||
|
||||
if (vecPos.x == 0.0 && vecPos.y == 0.0 && vecPos.z == 0.0) {
|
||||
WriteTimestampedLogEntry("KA_ERROR: KaPrivCreateLocationVariance (ka_i_weapon) - invalid vector returned from location");
|
||||
return loc;
|
||||
}
|
||||
|
||||
// randomize within given meter(s) of original vector position
|
||||
|
||||
float fX = (IntToFloat(Random(10) * iMeters) / 10.0);
|
||||
|
||||
int iXPosNeg = Random(2);
|
||||
|
||||
if (iXPosNeg) {
|
||||
|
||||
// positive variance
|
||||
|
||||
vecPos.x += fX;
|
||||
|
||||
//WriteTimestampedLogEntry("positive variance X - " + FloatToString(fX));
|
||||
|
||||
} else if (vecPos.x > fX) {
|
||||
|
||||
// negative variance
|
||||
|
||||
vecPos.x -= fX;
|
||||
|
||||
//WriteTimestampedLogEntry("negative variance X - " + FloatToString(fX));
|
||||
}
|
||||
|
||||
float fY = (IntToFloat(Random(10) * iMeters) / 10.0);
|
||||
|
||||
int iYPosNeg = Random(2);
|
||||
|
||||
if (iYPosNeg) {
|
||||
|
||||
// positive variance
|
||||
|
||||
vecPos.y += fY;
|
||||
|
||||
//WriteTimestampedLogEntry("positive variance Y - " + FloatToString(fY));
|
||||
|
||||
} else if (vecPos.y > fY) {
|
||||
|
||||
// negative variance
|
||||
|
||||
vecPos.y -= fY;
|
||||
|
||||
//WriteTimestampedLogEntry("negative variance Y - " + FloatToString(fY));
|
||||
}
|
||||
|
||||
location locReturn = Location(oArea, vecPos, 0.0);
|
||||
|
||||
return locReturn;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// string table at end of file /////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////
|
||||
////////////////////////////////
|
||||
///////////////////////////
|
||||
//////////////////////
|
||||
/////////////////
|
||||
// <Localization>
|
||||
//
|
||||
// Locale Language
|
||||
// "en" English
|
||||
// "it" Italian
|
||||
// "nl" Dutch
|
||||
// "es" Spanish
|
||||
// "fr" French
|
||||
// "de" German
|
||||
//
|
||||
// int - the string's associated reference in the sudo string table.
|
||||
// string - locale identifier, by default this is the English language.
|
||||
//
|
||||
string StringTable(int nStringRef, string sLCID)
|
||||
{
|
||||
string sString = "Error: Invalid string reference in localized string table in ka_i_weapon, for string reference: " + IntToString(nStringRef);
|
||||
|
||||
// check the local of the language
|
||||
|
||||
if ("en" == sLCID) { // English
|
||||
|
||||
// switch on the string reference from parameter
|
||||
|
||||
switch (nStringRef) {
|
||||
//
|
||||
// KaWeaponRange
|
||||
//
|
||||
case 0:
|
||||
sString = "Range: ";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return sString;
|
||||
}
|
||||
Reference in New Issue
Block a user