Compare commits

...

9 Commits

Author SHA1 Message Date
Jaysyn904
f032335869 Merge branch 'main' of https://gitea.raptio.us/Jaysyn/Battledale_PRC8 2025-06-13 20:42:35 -04:00
Jaysyn904
1c9cf0f081 Fixing copy / paste error
Fixing copy / paste error
2025-06-13 20:42:27 -04:00
Jaysyn904
bd3642f5c6 Updated for epic PrC expansion
Updated for epic PrC expansion.
Hooked up events for NUI spellcast menu.
Full compile.
2025-06-13 18:50:13 -04:00
Jaysyn904
50b5cdd24c Compiled PRC'd monster abilities
Compiled PRC'd monster abilities
2025-06-13 18:35:47 -04:00
Jaysyn904
03454e433b Update .gitignore 2025-04-03 22:08:10 -04:00
Jaysyn904
82f1ae6a7a Removed _release archive
Removed _release archive
2025-04-03 22:05:55 -04:00
Jaysyn904
09d0100931 Update for PRC8 function updates
Update for PRC8 function updates.  Full compile.  Updated release archive.
2025-02-13 12:36:58 -05:00
Jaysyn904
34f69e3221 Added repo avatar
Added repo avatar
2024-09-09 15:19:08 -04:00
Jaysyn904
4dba880acb Added ACP v4.1
Added ACP v4.1. Full compile.  Updated module name.  Updated release archive.
2024-09-08 18:23:43 -04:00
2924 changed files with 1035244 additions and 27134 deletions

4
.gitignore vendored
View File

@@ -1,3 +1,5 @@
*.mod
*.tlk
*.hak
*.md5
/_release

View File

@@ -4,4 +4,5 @@ Repository for the PRC'd version of the *Battledale: Pilgrim's Rest* persistent
## Requirements:
* PRC8
* CEP3
* CEP 3
* ACP v4.1

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);
nDC = 36;
PlayDragonBattleCry();
PRCPlayDragonBattleCry();
//Get first target in spell area
oTarget = GetFirstObjectInShape(SHAPE_SPELLCONE, 14.0, GetSpellTargetLocation(), TRUE);

Binary file not shown.

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