Hm. Time to test the new forum code posting capabilities...
Here's our Ruin script:
//::///////////////////////////////////////////////
//:: Greater Ruin
//:: X2_S2_Ruin
//:: Copyright (c) 2003 Bioware Corp.
//:://////////////////////////////////////////////
/*
// The caster deals 35d6 damage to a single target
fort save for half damage
*/
//:://////////////////////////////////////////////
//:: Created By: Andrew Nobbs
//:: Created On: Nov 18, 2002
//:://////////////////////////////////////////////
#include "hg_inc"
#include "ac_spell_inc"
#include "inc_draw"
void DoRuinSplat (object oTarget) {
float fRadiusEnd = 8.0;
float fHeightEnd = 8.0;
int nFrequency = 100;
float fRevolutions = 9.0;
float fTime = 1.5;
location lTarget = GetLocation(oTarget);
DrawSpring(0, VFX_COM_CHUNK_RED_BALLISTA, lTarget, 0.0, fRadiusEnd, 0.0, fHeightEnd, 0.0, 4, fRevolutions, fTime, 0.0, "z");
DrawSpring(0, VFX_COM_CHUNK_RED_BALLISTA, lTarget, 0.0, fRadiusEnd, 0.0, fHeightEnd, 0.0, 4, fRevolutions, fTime, 90.0, "z");
DrawSpring(0, VFX_COM_CHUNK_RED_BALLISTA, lTarget, 0.0, fRadiusEnd, 0.0, fHeightEnd, 0.0, 4, fRevolutions, fTime, 180.0, "z");
DrawSpring(0, VFX_COM_CHUNK_RED_BALLISTA, lTarget, 0.0, fRadiusEnd, 0.0, fHeightEnd, 0.0, 4, fRevolutions, fTime, 270.0, "z");
DrawSpiral(0, VFX_COM_BLOOD_LRG_RED, lTarget, 0.0, fRadiusEnd, 0.0, nFrequency, fRevolutions, fTime, 0.0, "z");
}
void DoRuinStrike (object oTarget, int nDeath) {
ApplyVisualAtLocation(VFX_FNF_SCREEN_SHAKE, GetLocation(oTarget));
if (nDeath == 2)
ApplyVisualToObject(VFX_IMP_REDUCE_ABILITY_SCORE, oTarget);
else
ApplyVisualToObject(VFX_FNF_GREATER_RUIN, oTarget);
ApplyVisualToObject(VFX_COM_BLOOD_CRT_RED, oTarget);
ApplyVisualToObject(VFX_COM_CHUNK_BONE_MEDIUM, oTarget);
}
void DoRuinDeath (object oTarget) {
ApplyEffectToObject(DURATION_TYPE_INSTANT, ExtraordinaryEffect(EffectDeath()), oTarget);
}
void DoRuinDamage (object oTarget, int bSaved, int nDeath) {
int nDam = d6(70);
if (bSaved)
nDam /= 2;
effect eDam = EffectDamage(nDam, (nDeath == 2 ? DAMAGE_TYPE_MAGICAL : DAMAGE_TYPE_POSITIVE), DAMAGE_POWER_PLUS_TWENTY);
ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget);
}
void main() {
struct SpellInfo si = GetEpicSpellInfo(OBJECT_SELF);
if (si.id < 0)
return;
if (GetLocalInt(si.caster, "NeedsRelog")) {
FloatingTextStringOnCreature("You cannot cast Greater Ruin until you log out and back in.", OBJECT_SELF, FALSE);
return;
}
int nDeath = 0;
float fDist = GetDistanceBetween(si.caster, si.target);
float fDelay = fDist / (3.0 * log(fDist) + 2.0);
if (GetIsObjectValid(si.item)) {
if (GetResRef(si.item) == "aa_str") {
if (GetLocalInt(si.caster, "NeedsRest")) {
FloatingTextStringOnCreature("You must rest before you can use this power!", si.caster, FALSE);
return;
}
nDeath = 2;
}
} else
nDeath = 1;
if (nDeath) {
if (!GetIsSpellTarget(si)) {
if (nDeath == 2) {
SetItemCharges(si.item, 3);
RestoreItemSpellUses(si.item);
FloatingTextStringOnCreature("You cannot use the Touch of Vecna on " + GetName(si.target) + "!", si.caster, FALSE);
} else {
IncrementRemainingFeatUses(si.caster, FEAT_EPIC_SPELL_RUIN);
FloatingTextStringOnCreature("You cannot use Greater Ruin on " + GetName(si.target) + "!", si.caster, FALSE);
}
return;
}
SignalEvent(si.target, EventSpellCastAt(si.caster, si.id));
if (nDeath == 2) {
int nTouch = TouchAttackMelee(si.target);
if (nTouch < 1) {
SetItemCharges(si.item, 3);
RestoreItemSpellUses(si.item);
return;
}
si.dc = GetHitDiceIncludingLLs(si.caster) + (nTouch == 2 ? 5 : 0);
} else {
si.dc = si.clevel + 5;
AddLocalInt(si.caster, "FeatUsed_" + IntToString(FEAT_EPIC_SPELL_RUIN), 1);
int nRemaining = GetLocalInt(si.caster, "FeatLimit_" + IntToString(FEAT_EPIC_SPELL_RUIN)) -
GetLocalInt(si.caster, "FeatUsed_" + IntToString(FEAT_EPIC_SPELL_RUIN));
if (nRemaining > 0) {
FloatingTextStringOnCreature("<c›þþ>You have " + IntToString(nRemaining) +
" uses of Greater Ruin left.</c>", si.caster, FALSE);
IncrementRemainingFeatUses(si.caster, FEAT_EPIC_SPELL_RUIN);
}
}
int bSaved = (GetSaveCheckResult(SAVING_THROW_FORT, si.target, si.dc, SAVING_THROW_TYPE_SPELL) > 0);
if (!bSaved) {
if (GetIsRuinImmune(si.target)) {
effect eVis = EffectVisualEffect(VFX_IMP_GLOBE_USE);
DelayCommand(fDelay + 0.1, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, si.target));
} else {
DoRuinStrike(si.target, nDeath);
/* only do the extra juicy vfx for a killshot */
DelayCommand(fDelay, DoRuinSplat(si.target));
DelayCommand(fDelay + 0.1, DoRuinDeath(si.target));
return;
}
}
DelayCommand(fDelay, DoRuinStrike(si.target, nDeath));
DelayCommand(fDelay + 0.1, DoRuinDamage(si.target, bSaved, nDeath));
} else if (GetIsSpellTarget(si)) {
SignalEvent(si.target, EventSpellCastAt(si.caster, si.id));
si.dc += GetCasterSpellFocus(SPELL_SCHOOL_EVOCATION, si.caster, si.clevel, si.class) * 2;
int bSaved = (GetSaveCheckResult(SAVING_THROW_FORT, si.target, si.dc, SAVING_THROW_TYPE_SPELL) > 0);
DelayCommand(fDelay, DoRuinStrike(si.target, nDeath));
DelayCommand(fDelay + 0.1, DoRuinDamage(si.target, bSaved, nDeath));
}
}
And here is the section of our rest script that handles the ruin variables:
int nAddES;
if (GetKnowsFeat(FEAT_EPIC_SPELL_RUIN, oPC)) {
if (GetSkillRank(SKILL_SPELLCRAFT, oPC, TRUE) >= 50)
nAddES++;
if (nSub == SUBRACE_KAORTI && GetHitDiceIncludingLLs(oPC) >= 40)
nAddES++;
if (nAddES)
SetLocalInt(oPC, "FeatLimit_" + IntToString(FEAT_EPIC_SPELL_RUIN), nAddES+1);
}
DeleteLocalInt(oPC, "FeatUsed_" + IntToString(FEAT_EPIC_SPELL_RUIN));
Pretty simple, once you look past the other code.
Also, WOOOOT for the return of real codeboxing on the bioboards! My days of passive-agressive griping about them are finally at and end. =D
Funky