// WILD MAGIC SYSTEM by Lex // Adapted to HCR system by Archaegeo #include "prc_inc_spells" // Set MATERCOMP to 0 to not use material components for those spells that need. object oMod=GetModule(); int MATERCOMP = 1; // Indicates magical normality int WM_NORMAL = 0; // Indicates lack of magical energy int WM_NULL = 1; // Indicates erratic magical energy int WM_WILD = 2; // Checks to see whether the spell script should not continue normally. // Use: if (WildMagicOverride()) { return; } // The function should be able to figure out the three parameters on its own. // If not, or if you are using it in a non-spell script, provide up to three // objects involved in the check. Leave any unused parameters as OBJECT_INVALID // to have them autodetect, or use the same object more than once. // Should work in item activation scripts! int WildMagicOverride(object oArea = OBJECT_INVALID, object oCaster = OBJECT_INVALID, object oTarget = OBJECT_INVALID); // Similar to WildMagicOverride, but does not include Wild effects. Mostly used // in situations where wild effects would be inappropriate, like in an AOE's // heartbeat and OnEnter scripts. int NullMagicOverride(object oArea = OBJECT_INVALID, object oCaster = OBJECT_INVALID, object oTarget = OBJECT_INVALID); // Modifies the magic state of oTarget. nState is one of // WM_NORMAL, WM_NULL, WM_WILD. Wild and Null magic stack, allowing // you to safely add and remove these effects without interfering with // other things that deal with these states. Modifying WM_NORMAL positively // will decrease the wild and null effects that much, while modifying it // negatively will remove all wild and null effects. void SetWMState(object oTarget, int nState, int nAmount=1); // Returns WM_NORMAL, WM_NULL, or WM_WILD. // If the object is both wild and null, WM_NULL is returned. int GetWMState(object oTarget); // Creates a Wild Magic area of effect. Creatures in the AOE // are considered Wild until they leave it. // EXPERIMENTAL. // Problems: Placeables don't seem to be affected by this, // so spells can be cast into the AOE as long as they target // either a placeable or a location. effect EffectWildMagicAOE(); // Creates a Null Magic area of effect. Creatures in the AOE // are considered null until they leave it. // EXPERIMENTAL. // Problems: Placeables don't seem to be affected by this, // so spells can be cast into the AOE as long as they target // either a placeable or a location. effect EffectNullMagicAOE(); // Removes all magical effects on a target. void RemoveMagicalEffects (object oTarget); // Used by WildMagicOverride() int GoWild(object oCaster, object oTarget, location lLocation); // Used by GoWild() void SpecialCast (int nSpell, object oTarget, location lLocation, int nCasterLevel, int nMetaMagic); // A creature or placeable nearby oTarget is randomly // chosen and returned. May return oTarget, especially // if there are few objects nearby. object GetRandomNearby(object oTarget=OBJECT_SELF); // Used by GoWild() void RandomCast(); // Checks for the old WM_STATE variable and makes the necessary // adjustments. Called by Get and SetWMState, probably no use // for it elsewhere. void DoWMUpdate(object oTarget) { int nState = GetLocalInt(oTarget, "WM_STATE"); DeleteLocalInt(oTarget, "WM_STATE"); if (!nState) return; SetWMState(oTarget, nState); } void SetWMState(object oTarget, int nState, int nAmount=1) { DoWMUpdate(oTarget); if (nState < 0 || nState > 2) nState = 0; if (nState == WM_NULL) { int x = GetLocalInt(oTarget, "MAGICSTATE_NULL") + nAmount; if (x < 0) x = 0; SetLocalInt(oTarget, "MAGICSTATE_NULL", x); int nType = GetObjectType(oTarget); // Dispel magical effects on the target if (x > 0) RemoveMagicalEffects(oTarget); } else if (nState == WM_WILD) { int x = GetLocalInt(oTarget, "MAGICSTATE_WILD") + nAmount; if (x < 0) x = 0; SetLocalInt(oTarget, "MAGICSTATE_WILD", x); } else if (nState = WM_NORMAL) { if (nAmount > 0) { SetWMState(oTarget, WM_NULL, -nAmount); SetWMState(oTarget, WM_WILD, -nAmount); } else { SetLocalInt(oTarget, "MAGICSTATE_NULL", 0); SetLocalInt(oTarget, "MAGICSTATE_WILD", 0); } } } int GetWMState(object oTarget) { DoWMUpdate(oTarget); int nNull = GetLocalInt(oTarget, "MAGICSTATE_NULL"); if (nNull > 0) return WM_NULL; int nWild = GetLocalInt(oTarget, "MAGICSTATE_WILD"); if (nWild > 0) return WM_WILD; return WM_NORMAL; } int NullMagicOverride(object oArea = OBJECT_INVALID, object oCaster = OBJECT_INVALID, object oTarget = OBJECT_INVALID) { int nModuleState = GetWMState(GetModule()); object oItem = GetItemActivated(); if (oItem == OBJECT_INVALID) oItem = PRCGetSpellCastItem(); int nItemState = GetWMState(oItem); location lTargetLocation; if (oCaster == OBJECT_INVALID) { oCaster = GetLastSpellCaster(); lTargetLocation = PRCGetSpellTargetLocation(); } if (oCaster == OBJECT_INVALID) { oCaster = GetItemActivator(); lTargetLocation = GetItemActivatedTargetLocation(); } if (oCaster == OBJECT_INVALID) { oCaster = OBJECT_SELF; lTargetLocation = GetLocation(OBJECT_SELF); } if (oTarget == OBJECT_INVALID) oTarget = PRCGetSpellTargetObject(); if (oTarget == OBJECT_INVALID) oTarget = GetItemActivatedTarget(); if (oTarget == OBJECT_INVALID) oTarget = oCaster; if (oArea == OBJECT_INVALID) oArea = GetArea(oCaster); if (oArea == OBJECT_INVALID) oArea = GetArea(oTarget); int nCasterState = GetWMState(oCaster); int nTargetState = GetWMState(oTarget); int nAreaState = GetWMState(oArea); if (nModuleState == 1 || nItemState == 1 || nCasterState == 1 || nTargetState == 1 || nAreaState == 1) { return 1; } if (oTarget == oCaster) { object oInvis = CreateObject(OBJECT_TYPE_PLACEABLE, "plc_invisobj", lTargetLocation); if (GetWMState(oInvis) == WM_NULL) { DestroyObject(oInvis); return 1; } DestroyObject(oInvis); } return 0; } int WildMagicOverride(object oArea = OBJECT_INVALID, object oCaster = OBJECT_INVALID, object oTarget = OBJECT_INVALID) { int nModuleState = GetWMState(GetModule()); object oItem = GetItemActivated(); if (oItem == OBJECT_INVALID) oItem = PRCGetSpellCastItem(); int nItemState = GetWMState(oItem); location lTargetLocation = PRCGetSpellTargetLocation(); if (oCaster == OBJECT_INVALID) { oCaster = GetLastSpellCaster(); lTargetLocation = PRCGetSpellTargetLocation(); } if (oCaster == OBJECT_INVALID) { oCaster = GetItemActivator(); lTargetLocation = GetItemActivatedTargetLocation(); } if (oCaster == OBJECT_INVALID) { oCaster = OBJECT_SELF; lTargetLocation = GetLocation(OBJECT_SELF); } if (oTarget == OBJECT_INVALID) oTarget = PRCGetSpellTargetObject(); if (oTarget == OBJECT_INVALID) oTarget = GetItemActivatedTarget(); if (oTarget == OBJECT_INVALID) oTarget = oCaster; if (oArea == OBJECT_INVALID) oArea = GetArea(oCaster); if (oArea == OBJECT_INVALID) oArea = GetArea(oTarget); // Null magic code moved int bIsNull = NullMagicOverride(oArea, oCaster, oTarget); if (bIsNull) { return bIsNull; } int nCasterState = GetWMState(oCaster); int nTargetState = GetWMState(oTarget); int nAreaState = GetWMState(oArea); if (nModuleState == 2 || nItemState == 2 || nCasterState == 2 || nTargetState == 2 || nAreaState == 2) { return GoWild(oCaster, oTarget, lTargetLocation); } if (oTarget == oCaster) { object oInvis = CreateObject(OBJECT_TYPE_PLACEABLE, "plc_invisobj", lTargetLocation); if (GetWMState(oInvis) == WM_WILD) { DestroyObject(oInvis); return GoWild(oCaster, oTarget, lTargetLocation); } DestroyObject(oInvis); } return 0; } int GoWild(object oCaster, object oTarget, location lLocation) { int nCasterLevel = PRCGetCasterLevel(oCaster); if (GetLocalInt(OBJECT_SELF, "WILDCASTING")) { DeleteLocalInt(OBJECT_SELF, "WILDCASTING"); return 0; } int nSpell = PRCGetSpellId(); int nMetaMagic = PRCGetMetaMagicFeat(); int nRoll = d100(); if (nRoll == 100) { object oNewTarget = GetRandomNearby(oTarget); float fDuration = IntToFloat(d20(2)*6); int nState = d2(); ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_IMP_HEAD_ODD), oNewTarget, fDuration); SetWMState(oNewTarget, nState); DelayCommand(fDuration, SetWMState(oNewTarget, nState, -1)); return 0; } else if (nRoll >= 96) { AssignCommand(oCaster, SpecialCast(nSpell, oTarget, lLocation, nCasterLevel, METAMAGIC_MAXIMIZE)); return 1; } else if (nRoll >= 86) { AssignCommand(oCaster, SpecialCast(nSpell, oTarget, lLocation, nCasterLevel, METAMAGIC_EXTEND)); return 1; } else if (nRoll >= 56) { return 0; } else if (nRoll >= 54) { CreateObject(OBJECT_TYPE_PLACEABLE, "plc_butterflies", GetLocation(oCaster)); return 1; } else if (nRoll >= 51) { AssignCommand(oCaster, SpecialCast(nSpell, oCaster, lLocation, nCasterLevel, nMetaMagic)); return 0; } else if (nRoll >= 41) { object oNewCaster = GetRandomNearby(oTarget); object oNewTarget = GetRandomNearby(oCaster); lLocation = GetLocation(oNewTarget); AssignCommand(oNewCaster, SpecialCast(nSpell, oNewTarget, lLocation, nCasterLevel, nMetaMagic)); return 1; } else if (nRoll >= 26) { return 1; } else if (nRoll >= 11) { object oNewTarget = GetRandomNearby(oCaster); lLocation = GetLocation(oNewTarget); AssignCommand(oCaster, SpecialCast(nSpell, oNewTarget, lLocation, nCasterLevel, nMetaMagic)); return 1; } else { AssignCommand(oCaster, RandomCast()); return 1; } } void SpecialCast (int nSpell, object oTarget, location lLocation, int nCasterLevel, int nMetaMagic) { object oCaster = OBJECT_SELF; SetLocalInt(oCaster, "WILDCASTING", TRUE); ClearAllActions(); if (oTarget == OBJECT_INVALID) { oTarget = GetNearestObjectToLocation(OBJECT_TYPE_CREATURE, lLocation); } AssignCommand(oCaster, ActionCastSpellAtObject(nSpell, oTarget, nMetaMagic, TRUE, nCasterLevel, PROJECTILE_PATH_TYPE_DEFAULT, TRUE)); DelayCommand(5.5, DeleteLocalInt(oCaster, "WILDCASTING")); } // To do: Get a better random spell chooser void RandomCast () { object oTarget = GetRandomNearby(OBJECT_SELF); location lLocation = GetLocation(oTarget); SpecialCast(Random(412), oTarget, lLocation, PRCGetCasterLevel(OBJECT_SELF), PRCGetMetaMagicFeat()); } object GetRandomNearby(object oTarget=OBJECT_SELF) { object oNewTarget; int nCounter = 0; int nType; while (1) { oNewTarget = GetNearestObject(OBJECT_TYPE_ALL, oTarget, nCounter); nType = GetObjectType(oNewTarget); if ((nType == OBJECT_TYPE_CREATURE || nType == OBJECT_TYPE_PLACEABLE) && d8() == 1) { break; // Target selected } if (nCounter++ > 20) { oNewTarget = oTarget; break; // Did not find random target, choose self as default } } return oNewTarget; } effect EffectWildMagicAOE() { int nAOE = AOE_PER_FOGKILL; return EffectAreaOfEffect(nAOE, "wm_aoe_e", "wm_aoe_h", "wm_aoe_x"); } effect EffectNullMagicAOE() { int nAOE =AOE_PER_FOGMIND; return EffectAreaOfEffect(nAOE, "nm_aoe_e", "nm_aoe_h", "nm_aoe_x"); } void RemoveMagicalEffects (object oTarget) { effect eEffect = GetFirstEffect(oTarget); while (GetIsEffectValid(eEffect)) { if (GetEffectSubType(eEffect) == SUBTYPE_MAGICAL) { RemoveEffect(oTarget, eEffect); } eEffect = GetNextEffect(oTarget); } }