Update for PRC8 function updates

Update for PRC8 function updates.  Full compile.  Updated release archive.
This commit is contained in:
Jaysyn904 2025-02-13 12:36:58 -05:00
parent 34f69e3221
commit 09d0100931
748 changed files with 1101 additions and 3 deletions

3
.gitignore vendored
View File

@ -1,3 +1,4 @@
*.mod
*.tlk
*.hak *.hak
*.md5 *.md5

View File

@ -0,0 +1,4 @@
:loop
"C:\NWN Work\nwnsc.exe" -o -w -n "C:\Games\Steam\steamapps\common\Neverwinter Nights" -i "D:\NWN Repos\Battledale_PRC8\_content\prc8_battle_top";"D:\NWN Repos\PRC8\nwn\nwnprc\trunk\include" "D:\NWN Repos\Battledale_PRC8\_content\prc8_battle_top\*.nss"
if %errorLevel% == -1 goto :loop
pause

View File

@ -0,0 +1,293 @@
#include "prc_inc_racial"
// returns TRUE if the PC qualifies for a multiclass penalty, FALSE if not
int Multipen(object oPC);
// Returns a float which can be more than 1 if the mob is higher level than the party, and less than
// 1 if it is lower level than the party. nDifference should be the difference between party level
// and mob CR
float getmodifier (int nDifference);
// Returns TRUE if the PC already has enough xp to take them to a level higher than they currently are
int PCHasExpToLevel(object oObject);
int Multipen(object oPC)
{
int nClass1=GetClassByPosition(1,oPC);
int nClass2=GetClassByPosition(2,oPC);
int nClass3=GetClassByPosition(3,oPC);
int nClass4=GetClassByPosition(4,oPC);
int nClass5=GetClassByPosition(5,oPC);
int nClass6=GetClassByPosition(6,oPC);
int nClass7=GetClassByPosition(7,oPC);
int nClass8=GetClassByPosition(8,oPC);
//::: Yeah, not doing this bullshit -Jaysyn
/* if ((nClass1==CLASS_TYPE_ARCANE_ARCHER)||(nClass1==CLASS_TYPE_ASSASSIN)|| (nClass1==CLASS_TYPE_BLACKGUARD)||(nClass1==CLASS_TYPE_HARPER)||(nClass1==CLASS_TYPE_SHADOWDANCER)||(nClass1==CLASS_TYPE_ANIMAL)||(nClass1==CLASS_TYPE_DIVINECHAMPION)||(nClass1==CLASS_TYPE_DRAGONDISCIPLE)||(nClass1==CLASS_TYPE_DWARVENDEFENDER)||(nClass1==CLASS_TYPE_PALEMASTER)||(nClass1==CLASS_TYPE_SHIFTER)||(nClass1==CLASS_TYPE_WEAPON_MASTER))
{
nClass1=CLASS_TYPE_INVALID;
}
if ((nClass2==CLASS_TYPE_ARCANE_ARCHER)||(nClass2==CLASS_TYPE_ASSASSIN)|| (nClass2==CLASS_TYPE_BLACKGUARD)||(nClass2==CLASS_TYPE_HARPER)||(nClass2==CLASS_TYPE_SHADOWDANCER)||(nClass2==CLASS_TYPE_ANIMAL)||(nClass2==CLASS_TYPE_DIVINECHAMPION)||(nClass2==CLASS_TYPE_DRAGONDISCIPLE)||(nClass2==CLASS_TYPE_DWARVENDEFENDER)||(nClass2==CLASS_TYPE_PALEMASTER)||(nClass2==CLASS_TYPE_SHIFTER)||(nClass2==CLASS_TYPE_WEAPON_MASTER))
{
nClass2=CLASS_TYPE_INVALID;
}
if ((nClass3==CLASS_TYPE_ARCANE_ARCHER)||(nClass3==CLASS_TYPE_ASSASSIN)|| (nClass3==CLASS_TYPE_BLACKGUARD)||(nClass3==CLASS_TYPE_HARPER)||(nClass3==CLASS_TYPE_SHADOWDANCER)||(nClass3==CLASS_TYPE_ANIMAL)||(nClass3==CLASS_TYPE_DIVINECHAMPION)||(nClass3==CLASS_TYPE_DRAGONDISCIPLE)||(nClass3==CLASS_TYPE_DWARVENDEFENDER)||(nClass3==CLASS_TYPE_PALEMASTER)||(nClass3==CLASS_TYPE_SHIFTER)||(nClass3==CLASS_TYPE_WEAPON_MASTER))
{
nClass3=CLASS_TYPE_INVALID;
}
*/
int nLevel1=GetLevelByClass(nClass1,oPC);
int nLevel2=GetLevelByClass(nClass2,oPC);
int nLevel3=GetLevelByClass(nClass3,oPC);
int nLevel4=GetLevelByClass(nClass4,oPC);
int nLevel5=GetLevelByClass(nClass5,oPC);
int nLevel6=GetLevelByClass(nClass6,oPC);
int nLevel7=GetLevelByClass(nClass7,oPC);
int nLevel8=GetLevelByClass(nClass8,oPC);
int nRace = GetRacialType(oPC);
int nFavoured;
// favoured == 99 means any
int nProblem1 = 0;
int nProblem2 = 0;
int nProblem3 = 0;
int nPenalty = 0;
if (nRace==RACIAL_TYPE_DWARF) //RACIAL_TYPE_DWARF
{nFavoured=CLASS_TYPE_FIGHTER;}
if (nRace==RACIAL_TYPE_ELF) //RACIAL_TYPE_elf
{nFavoured=CLASS_TYPE_WIZARD;}
if (nRace== RACIAL_TYPE_GNOME) //RACIAL_TYPE_gnome
{nFavoured=CLASS_TYPE_WIZARD;}
if (nRace==RACIAL_TYPE_HALFLING) //RACIAL_TYPE_halfling
{nFavoured=CLASS_TYPE_ROGUE;}
if (nRace== RACIAL_TYPE_HALFELF) //RACIAL_TYPE_halfelf
{nFavoured=99;}
if (nRace== RACIAL_TYPE_HALFORC) //RACIAL_TYPE_halforc
{nFavoured=CLASS_TYPE_BARBARIAN;}
if (nRace== RACIAL_TYPE_HUMAN) //RACIAL_TYPE_human
{nFavoured=99;}
if (nRace== RACIAL_TYPE_ANIMAL) //RACIAL_TYPE_animal
{nFavoured=99;}
/// first of all, check to see if the classes are roughly equal
int nEqual=0;
// as long as nEqual==0, they are roughly level.
if ((nClass1!=CLASS_TYPE_INVALID)&&(nClass2!=CLASS_TYPE_INVALID))
{
if ((nLevel1-nLevel2>1)||(nLevel2-nLevel1>1)) //the difference between class 1 and 2 is more than 1
{
nEqual=1;
nProblem1=1;
}
}
if ((nClass1!=CLASS_TYPE_INVALID)&&(nClass3!=CLASS_TYPE_INVALID))
{
if ((nLevel1-nLevel3>1)||(nLevel3-nLevel1>1)) //the difference between class 1 and 3 is more than 1
{
nEqual=1;
nProblem2=1;
}
}
if ((nClass2!=CLASS_TYPE_INVALID)&&(nClass3!=CLASS_TYPE_INVALID))
{
if ((nLevel2-nLevel3>1)||(nLevel3-nLevel2>1)) //the difference between class 1 and 2 is more than 1
{
nEqual=1;
nProblem3=1;
}
}
// if there is no problem here, return zero
if (nEqual==0)
{
return nPenalty;
}
// classes are unequal but are any of the unequal classes favoured?
// do humans and half elves first
if (nFavoured==99)
{
if ((nProblem1==1)&&(nProblem2==1)&&(nProblem3==1))
{
return 1;
}
else
{
return 0;
}
}
// now do everyone else
if (nProblem1==1)
{
if ((nClass1!=nFavoured)&&(nClass2!=nFavoured))
{
nPenalty=1;
}
}
if (nProblem2==1)
{
if ((nClass1!=nFavoured)&&(nClass3!=nFavoured))
{
nPenalty=1;
}
}
if (nProblem3==1)
{
if ((nClass2!=nFavoured)&&(nClass3!=nFavoured))
{
nPenalty=1;
}
}
return nPenalty;
}
float getmodifier (int nDifference)
{
// works out the modified for xp, based on the difference between the player or average party level and
// the cr of the mob.
float fModifier;
if (nDifference <= -7)
{
fModifier=1.9;
}
if (nDifference == -6)
{
fModifier=1.6;
}
if (nDifference == -5)
{
fModifier=1.5;
}
if (nDifference == -4)
{
fModifier=1.4;
}
if (nDifference == -3)
{
fModifier=1.3;
}
if (nDifference == -2)
{
fModifier=1.2;
}
if (nDifference == -1)
{
fModifier=1.1;
}
if (nDifference == 0)
{
fModifier=1.0;
}
if (nDifference == 1)
{
fModifier=1.0;
}
if (nDifference == 2)
{
fModifier=0.9;
}
if (nDifference == 3)
{
fModifier=0.7;
}
if (nDifference == 4)
{
fModifier=0.4;
}
if (nDifference == 5)
{
fModifier=0.2;
}
if (nDifference == 6)
{
fModifier=0.1;
}
if (nDifference == 7)
{
fModifier=0.05;
}
if (nDifference == 8)
{
fModifier=0.03;
}
if (nDifference == 9)
{
fModifier=0.02;
}
if (nDifference >= 10)
{
fModifier=0.01;
}
return fModifier;
}
int PCHasExpToLevel(object oObject)
{
int nHD = GetHitDice(oObject)+1;
//xp needed to be level nHD
int nXPNeeded = ((nHD * (nHD - 1)) / 2) * 1000;
if (GetXP(oObject)>=nXPNeeded)
{
return TRUE;
}
return FALSE;
}

View File

@ -0,0 +1,339 @@
#include "jw_exp_functions"
void givexp(object oMob,object oPC)
{
//KillAndReplaceLootable(OBJECT_SELF, TRUE);
float fCR;
if (GetLocalInt(OBJECT_SELF,"is_clone")==TRUE)
{
fCR=IntToFloat(GetHitDice(oMob))-1;
if (fCR<1.0)
{
fCR=1.0;
}
}
else
{
fCR=GetChallengeRating(oMob);
}
// nNumber gives you the number of players in the party. No penalty for using summoned mobs
// nHDcounter is the total HD of the party (players only)
// nHighlevel is the level of the highest person in the party;
int nNumber=0;
int nHDcounter=0;
int nHighlevel=1;
int nHD;
if (GetIsObjectValid(GetMaster(oPC)))
{
oPC=GetMaster(oPC);
}
if (!GetIsPC(oPC))
{
oPC=GetTrapCreator(oPC);
}
if (!GetIsPC(oPC))
{
return;
}
object oObject = GetFirstFactionMember(oPC, TRUE);
while (GetIsObjectValid(oObject) == TRUE)
{
nHD=GetHitDice(oObject);
nNumber++;
nHDcounter=nHDcounter+nHD;
if (nHD>nHighlevel)
{
nHighlevel=nHD;
}
oObject = GetNextFactionMember(oPC, TRUE);
}
// if the party has no members for some reason, return;
if (nNumber==0)
{
return;
}
/// the average level of the party is the total HD divided by the number of people
float fTotalHD=IntToFloat(nHDcounter);
float fAvlevel=fTotalHD/nNumber;
float fHighlevel=IntToFloat(nHighlevel);
float fLevel;
// the party level used to generate a level which xp is based on is fLevel.
// This is the avererage party level plus the highest level in the party divided by two.
// Eg if the average level is 5 but there is a level 10 in there, the party is
// treated as being level 7.5.
if (fHighlevel>fAvlevel)
{
fLevel=(fHighlevel+fAvlevel)/2;
}
else
{
fLevel=fAvlevel;
}
// fDifference is the party level we are using minus the challenge rating of the creature.
// so a level 7 mob killed by a level 9 group will have an fDifference of two.
// This indicates that the mob was a fairly easy challenge.
float fDifference=fLevel-fCR;
int nDifference=FloatToInt(fDifference);
// if the difference was more than 11, nobody gets anything.
if (nDifference>11)
{
oObject = GetFirstFactionMember(oPC, TRUE);
while (GetIsObjectValid(oObject) == TRUE)
{
SendMessageToPC(oObject,"Your party gains no experience from defeating "+GetName(oMob));
oObject = GetNextFactionMember(oPC, TRUE);
return;
}
}
// This calls the function at the top to check out how much the xp reward should
// be modified, based on fDifference. If fDifference is a positive number, then the
// modifier is less than one.
// For example, if the difference is four then the party will only get 0.3 experience
// for every one point of experience they could have earned if they were the same
// level as this mob.
// However if they are of a lower level than the mob, they get extra xp.
// It is worth fighting mobs of a higher level than yourself.
float fModifier = getmodifier(nDifference);
// The basic xp of any mob is it's challenge rating times 5.5. Ie first level mob gives 5.5
// second gives 11, 20th gives 110.
// A mob which is challenge rating 1/2 or 1/8 (such as kobolds level one and two
// or much of crypts level one) gives 5.0.
float fBasicxp;
if (fCR>=1.0)
{
fBasicxp=fCR*4.7;
}
else
{
fBasicxp=4.3;
}
// The exp will be shared out among the party. However the total xp pool
// is increased if the players are in a party. This is to lessen the bonus given
// to people who solo.
// A party of two will each get 80 per cent as much xp as either of them would have got for
// killing the mob solo.
// A party of 3 will each get 73 per cent of the exp which
// any of them would have got for killing the mob solo.
// solo. A party of six each gets 0.50 per cent of the exp they would have got if
// they had killed the mob solo.
// This means there is a great advantage to being in a party, as you can kill more mobs
// yet still get good exp.
// These figures ignore the adjustments from the levels of the players in the party.
// if more than four people are in the party, any future people do not add to the bonus.
float fPartybonus=1.0;
if (nNumber>1)
{
fPartybonus=(IntToFloat(nNumber));
fPartybonus=fPartybonus-1.0;
if (fPartybonus>4.0)
{
fPartybonus=4.0;
}
fPartybonus=fPartybonus*0.4;
fPartybonus=fPartybonus+1.0;
}
// the xp to be shared between the party is the xp the mob is worth (challenge rating times 4)
// times the modifer for the level difference (up or down depending on mob CR compared to party level)
// times any party modifier (up if the players are in a party)
float fPartyxp=fBasicxp*fModifier*fPartybonus;
// DEBUG
//SendMessageToAllDMs("fPartyxp "+FloatToString(fPartyxp)+" =fBasicxp "+FloatToString(fBasicxp)+" *fModifier "+FloatToString(fModifier)+ "*fPartybonus; "+FloatToString(fPartybonus));
// The xp for each player is then the partyxp divided by all the players (summoned
// creatures have no effect on this)
float fPlayerxp=fPartyxp/(IntToFloat(nNumber));
int nPlayerxp=FloatToInt(fPlayerxp);
// however we also want to make sure no players get more xp in a group
// than they would have done solo. This could happen if a high level char
// adventures with low level chars.
// no PC can ever get more exp than the strongest member of the faction could have got
// if they fought the mob solo
float fTestxp;
fDifference=fHighlevel-fCR;
nDifference=FloatToInt(fDifference);
fTestxp=fBasicxp*getmodifier(nDifference);
if (fPlayerxp>fTestxp)
{
fPlayerxp=fTestxp;
nPlayerxp=FloatToInt(fTestxp);
}
// fPlaydifference is going to be the difference between each PCs level and the highest level
// in the party
float fPlaydifference;
nHighlevel=FloatToInt(fHighlevel);
int nPlaylevel;
int nXPtogive;
float fMaxxp;
int nMaxxp;
oObject = GetFirstFactionMember(oPC, TRUE);
while (GetIsObjectValid(oObject) == TRUE)
{
// nDifference now is the level of each PC as we go through them in turn
// fTestxp is simply what they would have got if they killed the mob solo
nPlaylevel=GetHitDice(oObject);
nDifference=FloatToInt(IntToFloat(nPlaylevel)-fCR);
fTestxp=fPlayerxp;
// Work out the max xp a player of that level is allowed to get
// This is the xp they would have got for killing something 3 levels above themselves alone
fMaxxp=(fBasicxp*(IntToFloat(nPlaylevel)+2.0));
nMaxxp=FloatToInt(fMaxxp);
// fTestxp is equal to the XP each player will get if no modifications are needed.
// if the difference between the individual character and the mob is more than
// six, he gets no XP even if the party does.
// This system does leave open the possibility of high level chars helping
// low level chars. This is possibly open to abuse but is a deliberate
// feature to allow friends to adventure together even if they are of different
// levels.
if (GetArea(oPC)!=GetArea(oObject))
{
}
else
if (nDifference>11)
{
SendMessageToPC(oObject,"You cannot gain much experience for defeating "+GetName(oMob));
}
else
// otherwise, they get the exp we calculated above as long as they are not dead.
if (GetCurrentHitPoints(oObject)>=1)
{
nXPtogive=nPlayerxp;
//if (nXPtogive<1)
// {
// nXPtogive=1;
// }
// If the character is travelling in a higher level party, they get a penalty
if (nPlaylevel<(FloatToInt(fLevel)-8))
{
nDifference=FloatToInt(fLevel)-nPlaylevel-8;
fPlaydifference=getmodifier(nDifference);
fTestxp=fPlayerxp*fPlaydifference;
nXPtogive=FloatToInt(fPlayerxp*fPlaydifference);
}
/*
The server seems to be doing this on its own now
if (Multipen(oObject))
{
nXPtogive=FloatToInt(fTestxp*0.8);
SendMessageToPC(oObject,"Multiclass xp penalty affects you");
}
*/
if (nXPtogive>nMaxxp)
{
nXPtogive=nMaxxp;
}
// Now we give a bonus to lowbies
if (nPlaylevel<=3)
{
nXPtogive=nXPtogive*(5-nPlaylevel);
}
if (nXPtogive<2)
{
nXPtogive=2;
}
if (GetIsObjectValid(GetItemPossessedBy(oObject,"jw_exp_book")))
{
SendMessageToPC(oObject,"The Scholar's Tome in your inventory ensures you do not gain experience");
}
else
if ((PCHasExpToLevel(oObject)==TRUE)&&(nPlaylevel<=3))
{
SendMessageToPC(oObject,"You cannot gain any more experience this way until you train to your next level.");
}
else
{
SendMessageToPC(oObject,"You gain "+IntToString(nXPtogive)+" experience for defeating "+GetName(oMob));
GiveXPToCreature(oObject,nXPtogive);
}
}
oObject = GetNextFactionMember(oPC, TRUE);
}
}

View File

@ -0,0 +1,56 @@
//:: jw_inc_spells.nss
#include "x0_i0_transform"
// Trigger the nearest object with matching tag to convert.
// This should be called by the trigger object! It ASSUMES
// that GetEnteringObject() will work for OBJECT_SELF here.
void JWTriggerObjectTransform(string sCreature, int nVisualEffect=VFX_NONE, string sTag="tag_of_trigger");
int ScrollResist(object oCaster, object oTarget, float fDelay = 0.0);
int ScrollResist(object oCaster, object oTarget, float fDelay = 0.0)
{
oCaster=GetObjectByTag("PR_Zacharias");
if (fDelay > 0.5)
{
fDelay = fDelay - 0.1;
}
int nResist = ResistSpell(oCaster, oTarget);
effect eSR = EffectVisualEffect(VFX_IMP_MAGIC_RESISTANCE_USE);
effect eGlobe = EffectVisualEffect(VFX_IMP_GLOBE_USE);
effect eMantle = EffectVisualEffect(VFX_IMP_SPELL_MANTLE_USE);
if(nResist == 1) //Spell Resistance
{
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eSR, oTarget));
}
else if(nResist == 2) //Globe
{
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eGlobe, oTarget));
}
else if(nResist == 3) //Spell Mantle
{
if (fDelay > 0.5)
{
fDelay = fDelay - 0.1;
}
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eMantle, oTarget));
}
return nResist;
}
// Trigger the nearest object with matching tag to convert.
// This should be called by the trigger object! It ASSUMES
// that GetEnteringObject() will work for OBJECT_SELF here.
void JWTriggerObjectTransform(string sCreature, int nVisualEffect=VFX_NONE, string sTag="tag_of_trigger")
{
object oPC = GetEnteringObject();
if ( ! GetIsPC(oPC) ) { return; }
if (sTag=="tag_of_trigger")
{
sTag=GetTag(OBJECT_SELF);
}
object oOrigin = GetNearestObjectByTag(sTag);
TransformObjectToCreature(oOrigin, sCreature, nVisualEffect);
//DestroyObject(OBJECT_SELF, 5.0);
}

View File

@ -48,7 +48,7 @@ void main()
nDamage = d6(14); nDamage = d6(14);
nDC = 36; nDC = 36;
PlayDragonBattleCry(); PRCPlayDragonBattleCry();
//Get first target in spell area //Get first target in spell area
oTarget = GetFirstObjectInShape(SHAPE_SPELLCONE, 14.0, GetSpellTargetLocation(), TRUE); oTarget = GetFirstObjectInShape(SHAPE_SPELLCONE, 14.0, GetSpellTargetLocation(), TRUE);

Binary file not shown.

View File

@ -0,0 +1,405 @@
// 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);
}
}

Some files were not shown because too many files have changed in this diff Show More