Updated AMS marker feats. Removed arcane & divine marker feats. Updated Dread Necromancer for epic progression. Updated weapon baseitem models. Updated new weapons for crafting & npc equip. Updated prefix. Updated release archive.
411 lines
16 KiB
Plaintext
411 lines
16 KiB
Plaintext
//::///////////////////////////////////////////////
|
|
//:: Astral Construct manifestation include
|
|
//:: psi_inc_ac_manif
|
|
//:://////////////////////////////////////////////
|
|
//:://////////////////////////////////////////////
|
|
//:: Created By: Ornedan
|
|
//:: Created On: 23.01.2005
|
|
//:://////////////////////////////////////////////
|
|
|
|
#include "prc_inc_spells"
|
|
#include "psi_inc_psifunc"
|
|
#include "psi_inc_ac_const"
|
|
#include "inc_utility"
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
/* Constant defintions */
|
|
//////////////////////////////////////////////////
|
|
|
|
const int TEMP_HENCH_COUNT = 150;
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
/* Structure definitions */
|
|
//////////////////////////////////////////////////
|
|
|
|
// A structure containing appearance references
|
|
struct ac_forms{
|
|
int Appearance1, Appearance1Alt;
|
|
int Appearance2, Appearance2Alt;
|
|
int Appearance3, Appearance3Alt;
|
|
int Appearance4, Appearance4Alt;
|
|
};
|
|
|
|
//////////////////////////////////////////////////
|
|
/* Function prototypes */
|
|
//////////////////////////////////////////////////
|
|
|
|
void DoAstralConstructCreation(struct manifestation manif, location locTarget, int nACLevel,
|
|
int nOptionFlags, int nResElemFlags, int nETchElemFlags, int nEBltElemFlags);
|
|
|
|
void DoDespawn(object oConstruct, int bDoVFX = TRUE);
|
|
void DoDespawnAux(object oManifester, float fDur);
|
|
void DoSummonVFX(location locTarget, int nACLevel);
|
|
void DoUnsummonVFX(location locTarget, int nACLevel);
|
|
|
|
struct ac_forms GetAppearancessForLevel(int nLevel);
|
|
int GetAppearanceForConstruct(int nACLevel, int nOptionFlags, int nCheck);
|
|
int GetUseAltAppearances(int nOptionFlags);
|
|
string GetResRefForConstruct(int nACLevel, int nOptionFlags);
|
|
int GetHighestCraftSkillValue(object oCreature);
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
/* Function defintions */
|
|
//////////////////////////////////////////////////
|
|
|
|
// Summons the specified Astral Construct at the given location
|
|
// Handling of the flags (other than the Buff series) is done
|
|
// in the creature's OnSpawn eventscript
|
|
void DoAstralConstructCreation(struct manifestation manif, location locTarget, int nACLevel,
|
|
int nOptionFlags, int nResElemFlags, int nETchElemFlags, int nEBltElemFlags)
|
|
{
|
|
// Get the resref for the AC
|
|
string sResRef = GetResRefForConstruct(nACLevel, nOptionFlags);
|
|
|
|
// Get the constructs duration. 1 round / level. Metapsionic Extend can be applied.
|
|
float fDur = 6.0 * GetManifesterLevel(manif.oManifester);
|
|
if(GetPRCSwitch(PRC_PSI_ASTRAL_CONSTRUCT_DUR_MOD) > 0)
|
|
fDur *= GetPRCSwitch(PRC_PSI_ASTRAL_CONSTRUCT_DUR_MOD);
|
|
if(manif.bExtend)
|
|
fDur *= 2;
|
|
|
|
// Add in 1 round of duration to account for AI disorientation in the beginning
|
|
fDur += 6.0f;
|
|
|
|
/* Until Bioware "fixes" Jasperre's multisummon trick, AC are added as genuine summons instead of henchies
|
|
// We need to make sure that we can add the new construct as henchman
|
|
int nMaxHenchmen = GetMaxHenchmen();
|
|
SetMaxHenchmen(TEMP_HENCH_COUNT);
|
|
|
|
// Add the AC as henchman
|
|
object oConstruct = CreateObject(OBJECT_TYPE_CREATURE, sResRef, locTarget);
|
|
AddHenchman(oManifester, oConstruct);
|
|
|
|
// And set the max henchmen count back to original, so we won't mess up the module
|
|
SetMaxHenchmen(nMaxHenchmen);
|
|
|
|
*/
|
|
|
|
|
|
// Do multisummon trick
|
|
int bMultisummon = GetPRCSwitch(PRC_MULTISUMMON);
|
|
int i = 1;
|
|
object oCheck = GetAssociate(ASSOCIATE_TYPE_SUMMONED, manif.oManifester, i);
|
|
while(GetIsObjectValid(oCheck))
|
|
{
|
|
//DoDebug("DoAstralConstructCreation: Handling associate " + DebugObject2Str(oCheck));
|
|
// If multisummon is active, make all summons indestructible. If not, only make astral constructs
|
|
if(bMultisummon || GetStringLeft(GetTag(oCheck), 14) == "psi_astral_con")
|
|
{
|
|
AssignCommand(oCheck, SetIsDestroyable(FALSE, FALSE, FALSE));
|
|
AssignCommand(oCheck, DelayCommand(1.0, SetIsDestroyable(TRUE, FALSE, FALSE)));
|
|
oCheck = GetAssociate(ASSOCIATE_TYPE_SUMMONED, manif.oManifester, ++i);
|
|
}
|
|
}
|
|
|
|
// Do actual summon effect
|
|
ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, EffectSummonCreature(sResRef), locTarget, fDur + 0.5);
|
|
|
|
/* For use if need to return to henchman setup
|
|
|
|
// Add the locals to the construct
|
|
SetLocalInt(oConstruct, ASTRAL_CONSTRUCT_LEVEL, nACLevel);
|
|
SetLocalInt(oConstruct, ASTRAL_CONSTRUCT_OPTION_FLAGS, nOptionFlags);
|
|
SetLocalInt(oConstruct, ASTRAL_CONSTRUCT_RESISTANCE_FLAGS, nResElemFlags);
|
|
SetLocalInt(oConstruct, ASTRAL_CONSTRUCT_ENERGY_TOUCH_FLAGS, nETchElemFlags);
|
|
SetLocalInt(oConstruct, ASTRAL_CONSTRUCT_ENERGY_BOLT_FLAGS, nEBltElemFlags);
|
|
|
|
|
|
// Do appearance switching
|
|
int nCraft = GetHighestCraftSkillValue(oManifester);
|
|
int nCheck = d20() + nCraft;
|
|
|
|
int nAppearance = GetAppearanceForConstruct(nACLevel, nOptionFlags, nCheck);
|
|
SetCreatureAppearanceType(oConstruct, nAppearance);
|
|
*/
|
|
|
|
// Do VFX
|
|
DoSummonVFX(locTarget, nACLevel);
|
|
|
|
// Schedule unsummoning. No need to hurry this one, so give it a larger delay
|
|
// in order to avoid hogging too much resources over a short span of time.
|
|
DelayCommand(2.0, DoDespawnAux(manif.oManifester, fDur));
|
|
}
|
|
|
|
|
|
// A function to handle the AC's duration running out
|
|
// Some paranoia present to make sure nothing could accidentally
|
|
// make it permanent
|
|
void DoDespawn(object oConstruct, int bDoVFX = TRUE)
|
|
{
|
|
if(GetIsObjectValid(oConstruct)){
|
|
DestroyObject(oConstruct);
|
|
DelayCommand(0.15f, MyDestroyObject(oConstruct)); // The paranoia bit :D
|
|
if(bDoVFX) DoUnsummonVFX(GetLocation(oConstruct), GetLocalInt(oConstruct, ASTRAL_CONSTRUCT_LEVEL));
|
|
}
|
|
}
|
|
|
|
// An auxiliary to be delayed so that a reference to the just created AC can be found
|
|
void DoDespawnAux(object oManifester, float fDur){
|
|
// Find the newly added construct
|
|
object oConstruct = OBJECT_INVALID;
|
|
int i = 1;
|
|
object oCheck = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oManifester, i);
|
|
while(GetIsObjectValid(oCheck))
|
|
{
|
|
if(!GetLocalInt(oCheck, "UnsummonScheduled") && GetStringLeft(GetTag(oCheck), 14) == "psi_astral_con")
|
|
{
|
|
oConstruct = oCheck;
|
|
break;
|
|
}
|
|
i++;
|
|
oCheck = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oManifester, i);
|
|
}
|
|
SetLocalInt(oConstruct, "UnsummonScheduled", TRUE);
|
|
|
|
if(DEBUG) DoDebug("Found the just added astral construct: " + (GetIsObjectValid(oConstruct) ? "true":"false") + "\nSummon name: " + GetName(oConstruct) + "\nTotal summons: " + IntToString(i), oManifester);
|
|
|
|
// Schedule unsummoning. Done this way to skip the default unsummoning VFX.
|
|
DelayCommand(fDur - 2.0, DoDespawn(oConstruct));
|
|
}
|
|
|
|
// Does a visual choreography that depends on the level of the construct being created.
|
|
// Higher level constructs get neater VFX :D
|
|
void DoSummonVFX(location locTarget, int nACLevel){
|
|
DrawSpiral(0, 263, locTarget, IntToFloat(nACLevel) * 0.75 + 0.5, 0.4, 1.0, 60, 16.899999619, 3.0, 4.0);
|
|
}
|
|
|
|
void DoUnsummonVFX(location locTarget, int nACLevel){
|
|
DrawSpiral(0, 263, locTarget, 0.4, IntToFloat(nACLevel) * 0.75 + 0.5, 1.0, 60, 16.899999619, 3.0, 4.0);
|
|
}
|
|
|
|
|
|
struct ac_forms GetAppearancesForLevel(int nLevel)
|
|
{
|
|
struct ac_forms toReturn;
|
|
|
|
switch(nLevel)
|
|
{
|
|
case 1:
|
|
toReturn.Appearance1 = APPEARANCE_TYPE_RAT;
|
|
toReturn.Appearance1Alt = 387; //Dire Rat
|
|
|
|
toReturn.Appearance2 = APPEARANCE_TYPE_INTELLECT_DEVOURER;
|
|
toReturn.Appearance2Alt = APPEARANCE_TYPE_WAR_DEVOURER;
|
|
|
|
toReturn.Appearance3 = APPEARANCE_TYPE_PSEUDODRAGON;
|
|
toReturn.Appearance3Alt = APPEARANCE_TYPE_PSEUDODRAGON;
|
|
|
|
toReturn.Appearance4 = APPEARANCE_TYPE_FAERIE_DRAGON;
|
|
toReturn.Appearance4Alt = APPEARANCE_TYPE_FAERIE_DRAGON;
|
|
|
|
return toReturn;
|
|
case 2:
|
|
toReturn.Appearance1 = APPEARANCE_TYPE_GARGOYLE;
|
|
toReturn.Appearance1Alt = APPEARANCE_TYPE_GARGOYLE;
|
|
|
|
toReturn.Appearance2 = APPEARANCE_TYPE_BAT_HORROR;
|
|
toReturn.Appearance2Alt = APPEARANCE_TYPE_HELMED_HORROR;
|
|
|
|
toReturn.Appearance3 = APPEARANCE_TYPE_ASABI_WARRIOR;
|
|
toReturn.Appearance3Alt = APPEARANCE_TYPE_LIZARDFOLK_WARRIOR_B;
|
|
|
|
toReturn.Appearance4 = APPEARANCE_TYPE_WERECAT;
|
|
toReturn.Appearance4Alt = APPEARANCE_TYPE_WERECAT;
|
|
|
|
return toReturn;
|
|
case 3:
|
|
toReturn.Appearance1 = APPEARANCE_TYPE_FORMIAN_WORKER;
|
|
toReturn.Appearance1Alt = APPEARANCE_TYPE_FORMIAN_WORKER;
|
|
|
|
toReturn.Appearance2 = APPEARANCE_TYPE_FORMIAN_WARRIOR;
|
|
toReturn.Appearance2Alt = APPEARANCE_TYPE_FORMIAN_WARRIOR;
|
|
|
|
toReturn.Appearance3 = APPEARANCE_TYPE_FORMIAN_MYRMARCH;
|
|
toReturn.Appearance3Alt = APPEARANCE_TYPE_FORMIAN_MYRMARCH;
|
|
|
|
toReturn.Appearance4 = APPEARANCE_TYPE_FORMIAN_QUEEN;
|
|
toReturn.Appearance4Alt = APPEARANCE_TYPE_FORMIAN_QUEEN;
|
|
|
|
return toReturn;
|
|
case 4:
|
|
toReturn.Appearance1 = 416; // Deep Rothe
|
|
toReturn.Appearance1Alt = 416;
|
|
|
|
toReturn.Appearance2 = APPEARANCE_TYPE_MANTICORE;
|
|
toReturn.Appearance2Alt = APPEARANCE_TYPE_MANTICORE;
|
|
|
|
toReturn.Appearance3 = APPEARANCE_TYPE_BASILISK;
|
|
toReturn.Appearance3Alt = APPEARANCE_TYPE_GORGON;
|
|
|
|
toReturn.Appearance4 = APPEARANCE_TYPE_DEVIL;
|
|
toReturn.Appearance4Alt = 468; // Golem, Demonflesh
|
|
|
|
return toReturn;
|
|
case 5:
|
|
toReturn.Appearance1 = APPEARANCE_TYPE_GOLEM_FLESH;
|
|
toReturn.Appearance1Alt = APPEARANCE_TYPE_GOLEM_FLESH;
|
|
|
|
toReturn.Appearance2 = APPEARANCE_TYPE_GOLEM_STONE;
|
|
toReturn.Appearance2Alt = APPEARANCE_TYPE_GOLEM_STONE;
|
|
|
|
toReturn.Appearance3 = APPEARANCE_TYPE_GOLEM_CLAY;
|
|
toReturn.Appearance3Alt = APPEARANCE_TYPE_GOLEM_CLAY;
|
|
|
|
toReturn.Appearance4 = 420; // Golem, Mithril
|
|
toReturn.Appearance4Alt = 420;
|
|
|
|
return toReturn;
|
|
case 6:
|
|
toReturn.Appearance1 = APPEARANCE_TYPE_TROLL;
|
|
toReturn.Appearance1Alt = APPEARANCE_TYPE_TROLL;
|
|
|
|
toReturn.Appearance2 = APPEARANCE_TYPE_ETTERCAP;
|
|
toReturn.Appearance2Alt = APPEARANCE_TYPE_ETTERCAP;
|
|
|
|
toReturn.Appearance3 = APPEARANCE_TYPE_UMBERHULK;
|
|
toReturn.Appearance3Alt = APPEARANCE_TYPE_UMBERHULK;
|
|
|
|
toReturn.Appearance4 = APPEARANCE_TYPE_MINOTAUR_SHAMAN;
|
|
toReturn.Appearance4Alt = APPEARANCE_TYPE_MINOGON;
|
|
|
|
return toReturn;
|
|
case 7:
|
|
toReturn.Appearance1 = APPEARANCE_TYPE_SPIDER_DIRE;
|
|
toReturn.Appearance1Alt = APPEARANCE_TYPE_SPIDER_DIRE;
|
|
|
|
toReturn.Appearance2 = APPEARANCE_TYPE_SPIDER_SWORD;
|
|
toReturn.Appearance2Alt = APPEARANCE_TYPE_SPIDER_SWORD;
|
|
|
|
toReturn.Appearance3 = 446; // Drider, Female
|
|
toReturn.Appearance3Alt = 446;
|
|
|
|
toReturn.Appearance4 = 407; // Drider, Chief
|
|
toReturn.Appearance4Alt = 407;
|
|
|
|
return toReturn;
|
|
case 8:
|
|
toReturn.Appearance1 = APPEARANCE_TYPE_HOOK_HORROR;
|
|
toReturn.Appearance1Alt = APPEARANCE_TYPE_VROCK;
|
|
|
|
toReturn.Appearance2 = 427; // Slaad, White
|
|
toReturn.Appearance2Alt = 427;
|
|
|
|
toReturn.Appearance3 = APPEARANCE_TYPE_GREY_RENDER;
|
|
toReturn.Appearance3Alt = APPEARANCE_TYPE_GREY_RENDER;
|
|
|
|
toReturn.Appearance4 = APPEARANCE_TYPE_GREY_RENDER;
|
|
toReturn.Appearance4Alt = APPEARANCE_TYPE_GREY_RENDER;
|
|
|
|
return toReturn;
|
|
case 9:
|
|
toReturn.Appearance1 = APPEARANCE_TYPE_ELEMENTAL_AIR_ELDER;
|
|
toReturn.Appearance1Alt = APPEARANCE_TYPE_ELEMENTAL_AIR_ELDER;
|
|
|
|
toReturn.Appearance2 = APPEARANCE_TYPE_GIANT_FROST_FEMALE;
|
|
toReturn.Appearance2Alt = APPEARANCE_TYPE_GIANT_FROST_FEMALE;
|
|
|
|
toReturn.Appearance3 = 418; // Dragon, Shadow
|
|
toReturn.Appearance3Alt = 418;
|
|
|
|
toReturn.Appearance4 = 471; // Mephisto, Normal
|
|
toReturn.Appearance4Alt = 471;
|
|
|
|
return toReturn;
|
|
|
|
default:{
|
|
string sErr = "psi_inc_ac_manif: GetAppearancesForLevel(): ERROR: Erroneous value for nLevel: " + IntToString(nLevel);
|
|
if(DEBUG) DoDebug(sErr);
|
|
else WriteTimestampedLogEntry(sErr);
|
|
}
|
|
}
|
|
|
|
return toReturn;
|
|
}
|
|
|
|
|
|
int GetAppearanceForConstruct(int nACLevel, int nOptionFlags, int nCheck)
|
|
{
|
|
int bUse2da = GetPRCSwitch(PRC_PSI_ASTRAL_CONSTRUCT_USE_2DA);
|
|
int bUseAlt = GetUseAltAppearances(nOptionFlags);
|
|
int nNum = nCheck < AC_APPEARANCE_CHECK_HIGH ?
|
|
nCheck < AC_APPEARANCE_CHECK_MEDIUM ?
|
|
nCheck < AC_APPEARANCE_CHECK_LOW ? 1
|
|
: 2
|
|
: 3
|
|
: 4;
|
|
// If we use 2da, get the data from there
|
|
if(bUse2da)
|
|
{
|
|
nNum += (nACLevel - 1) * 4 - 1;
|
|
|
|
return StringToInt(Get2DACache("ac_appearances", bUseAlt ? "AltAppearance" : "NormalAppearance", nNum));
|
|
}
|
|
|
|
// We don't so get it from GetAppearancesForLevel
|
|
|
|
struct ac_forms appearancelist = GetAppearancesForLevel(nACLevel);
|
|
|
|
switch(nNum)
|
|
{
|
|
case 1: return bUseAlt ? appearancelist.Appearance1Alt : appearancelist.Appearance1;
|
|
case 2: return bUseAlt ? appearancelist.Appearance2Alt : appearancelist.Appearance2;
|
|
case 3: return bUseAlt ? appearancelist.Appearance3Alt : appearancelist.Appearance3;
|
|
case 4: return bUseAlt ? appearancelist.Appearance4Alt : appearancelist.Appearance4;
|
|
|
|
default:{
|
|
string sErr = "psi_inc_ac_manif: GetAppearanceForConstruct(): ERROR: Erroneous value for nNum: " + IntToString(nNum);
|
|
if(DEBUG) DoDebug(sErr);
|
|
else WriteTimestampedLogEntry(sErr);
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
int GetUseAltAppearances(int nOptionFlags)
|
|
{ // Buff series
|
|
return nOptionFlags & ASTRAL_CONSTRUCT_OPTION_BUFF ||
|
|
nOptionFlags & ASTRAL_CONSTRUCT_OPTION_IMP_BUFF ||
|
|
nOptionFlags & ASTRAL_CONSTRUCT_OPTION_EXTRA_BUFF ||
|
|
// Deflection series
|
|
nOptionFlags & ASTRAL_CONSTRUCT_OPTION_DEFLECTION ||
|
|
nOptionFlags & ASTRAL_CONSTRUCT_OPTION_HEAVY_DEFLECT ||
|
|
nOptionFlags & ASTRAL_CONSTRUCT_OPTION_EXTREME_DEFLECT ||
|
|
// Damage Reduction Series
|
|
nOptionFlags & ASTRAL_CONSTRUCT_OPTION_IMP_DAM_RED ||
|
|
nOptionFlags & ASTRAL_CONSTRUCT_OPTION_EXTREME_DAM_RED;
|
|
}
|
|
|
|
|
|
string GetResRefForConstruct(int nACLevel, int nOptionFlags)
|
|
{
|
|
string sResRef = "psi_astral_con" + IntToString(nACLevel);
|
|
string sSuffix;
|
|
|
|
// Check whether we need a resref with buff applied
|
|
if(nOptionFlags & ASTRAL_CONSTRUCT_OPTION_BUFF)
|
|
sSuffix += "a";
|
|
else if(nOptionFlags & ASTRAL_CONSTRUCT_OPTION_IMP_BUFF)
|
|
sSuffix += "b";
|
|
else if(nOptionFlags & ASTRAL_CONSTRUCT_OPTION_EXTRA_BUFF)
|
|
sSuffix += "c";
|
|
|
|
return sResRef + sSuffix;
|
|
}
|
|
|
|
|
|
int GetHighestCraftSkillValue(object oCreature)
|
|
{
|
|
int nArmor = GetSkillRank(SKILL_CRAFT_ARMOR, oCreature);
|
|
int nTrap = GetSkillRank(SKILL_CRAFT_TRAP, oCreature);
|
|
int nWeapon = GetSkillRank(SKILL_CRAFT_WEAPON, oCreature);
|
|
|
|
return nArmor > nTrap ?
|
|
nArmor > nWeapon ? nArmor : nWeapon
|
|
: nTrap > nWeapon ? nTrap : nWeapon;
|
|
}
|