Bugfixing pass
Bugfixing pass. Spawn swapovers. Broom!
This commit is contained in:
185
_module/nss/_inc_battlecry_.nss
Normal file
185
_module/nss/_inc_battlecry_.nss
Normal file
@@ -0,0 +1,185 @@
|
||||
///////////////////////////////////
|
||||
// Carcerian's BattleCry Script //
|
||||
// "Evil Dead" Edition //
|
||||
///////////////////////////////////
|
||||
|
||||
#include "NW_I0_GENERIC"
|
||||
|
||||
const int BattleCryChance = 15;
|
||||
const int CombatCryChance = 20;
|
||||
const int DeathCryChance = 20;
|
||||
const int CustomUndeadChance = 50;
|
||||
|
||||
const string COLOR_RED = "<c<> >";
|
||||
const string COLOR_DARK = "<cSSS>";
|
||||
const string COLOR_GREEN = "<c <20> >";
|
||||
const string COLOR_WHITE = "<c<><63><EFBFBD>>";
|
||||
const string COLOR_VIOLET = "<c<> <20>>";
|
||||
const string COLOR_YELLOW = "<c<><63> >";
|
||||
|
||||
int HasSpoken()
|
||||
{
|
||||
if (GetLocalInt(OBJECT_SELF,"HASSPOKEN")) return 1;
|
||||
SetLocalInt(OBJECT_SELF,"HASSPOKEN",1);
|
||||
DelayCommand(IntToFloat(d10(4)),SetLocalInt(OBJECT_SELF,"HASSPOKEN",0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DoUndeadChatter()
|
||||
{
|
||||
string sMyTag = GetTag(OBJECT_SELF);
|
||||
if ((FindSubString(sMyTag,"SKEL")>-1)||(FindSubString(sMyTag,"MOHRG")>-1))
|
||||
{
|
||||
switch (d3()) // Skeletons
|
||||
{
|
||||
case 1 : ActionSpeakString(COLOR_WHITE+"I got a bone to pick with you!",TALKVOLUME_TALK); break;
|
||||
case 2 : ActionSpeakString(COLOR_WHITE+"Forward, you worthless bags of bones!",TALKVOLUME_TALK); break;
|
||||
case 3 : ActionSpeakString(COLOR_WHITE+"CHARGE!",TALKVOLUME_TALK); break;
|
||||
}
|
||||
}
|
||||
else if (FindSubString(sMyTag,"ZOMB")>-1)
|
||||
{
|
||||
if (Random(2)) ActionSpeakString(COLOR_GREEN+"Brains!",TALKVOLUME_TALK);
|
||||
else ActionSpeakString(COLOR_GREEN+"BRAINS!",TALKVOLUME_TALK);
|
||||
// "More brains!"
|
||||
}
|
||||
else if ((FindSubString(sMyTag,"GHOUL")>-1)||(FindSubString(sMyTag,"GHAST")>-1)
|
||||
||(FindSubString(sMyTag,"WIGHT")>-1))
|
||||
{
|
||||
switch (d4()) // Flesh Eaters
|
||||
{
|
||||
case 1 : ActionSpeakString(COLOR_GREEN+"I'll feast on your entrails!",TALKVOLUME_TALK); break;
|
||||
case 2 : ActionSpeakString(COLOR_GREEN+"FOOD!",TALKVOLUME_TALK); break;
|
||||
case 3 : ActionSpeakString(COLOR_GREEN+"Live ones!!",TALKVOLUME_TALK); break;
|
||||
case 4 : ActionSpeakString(COLOR_GREEN+"FLESSSSHHHH!!!",TALKVOLUME_TALK); break;
|
||||
}
|
||||
}
|
||||
else if ((FindSubString(sMyTag,"WRAITH")>-1)||(FindSubString(sMyTag,"ALLIP")>-1)
|
||||
||(FindSubString(sMyTag,"Bodak")>-1)||(FindSubString(sMyTag,"SHADOW")>-1)
|
||||
||(FindSubString(sMyTag,"SHFIEND")>-1)||(FindSubString(sMyTag,"SPECTRE")>-1))
|
||||
{
|
||||
switch (d4()) // Soul Eaters
|
||||
{
|
||||
case 1 : ActionSpeakString(COLOR_VIOLET+"I'll swallow your soul!",TALKVOLUME_TALK); break;
|
||||
case 2 : ActionSpeakString(COLOR_VIOLET+"Your soul will be mine!",TALKVOLUME_TALK); break;
|
||||
case 3 : ActionSpeakString(COLOR_VIOLET+"Mine!!!!",TALKVOLUME_TALK); break;
|
||||
case 4 : ActionSpeakString(COLOR_VIOLET+"The darkness calls for you...",TALKVOLUME_TALK); break;
|
||||
}
|
||||
}
|
||||
else switch (d6()) // Generic Undead
|
||||
{
|
||||
case 1 : ActionSpeakString(COLOR_RED+"I'll swallow your soul!",TALKVOLUME_TALK); break;
|
||||
case 2 : ActionSpeakString(COLOR_RED+"Blood and souls!",TALKVOLUME_TALK); break;
|
||||
case 3 : ActionSpeakString(COLOR_RED+"Joinnnn usssssssss!",TALKVOLUME_TALK); break;
|
||||
case 4 : ActionSpeakString(COLOR_RED+"For the Master!",TALKVOLUME_TALK); break;
|
||||
case 5 : ActionSpeakString(COLOR_RED+"For the Master!",TALKVOLUME_TALK); break;
|
||||
case 6 : ActionSpeakString(COLOR_RED+"One by one we will take you!",TALKVOLUME_TALK); break;
|
||||
}
|
||||
}
|
||||
|
||||
// For use on perception
|
||||
void DoBattleCry()
|
||||
{ //if undead spotted "i see dead people!" "Dead ahead!"
|
||||
if (d100()<=BattleCryChance)
|
||||
{
|
||||
if (HasSpoken()) return;
|
||||
if ((GetRacialType(OBJECT_SELF) == RACIAL_TYPE_UNDEAD)&&(d100()<=CustomUndeadChance))
|
||||
{
|
||||
DoUndeadChatter();
|
||||
}
|
||||
else switch (d10())
|
||||
{
|
||||
case 1: PlayVoiceChat(VOICE_CHAT_ATTACK); break;
|
||||
case 2: PlayVoiceChat(VOICE_CHAT_BATTLECRY1); break;
|
||||
case 3: PlayVoiceChat(VOICE_CHAT_BATTLECRY2); break;
|
||||
case 4: PlayVoiceChat(VOICE_CHAT_BATTLECRY3); break;
|
||||
case 5: PlayVoiceChat(VOICE_CHAT_THREATEN); break;
|
||||
case 6: PlayVoiceChat(VOICE_CHAT_TAUNT); break;
|
||||
case 7: PlayVoiceChat(VOICE_CHAT_ENEMIES); break;
|
||||
case 8: PlayVoiceChat(VOICE_CHAT_CHEER); break;
|
||||
case 9: PlayVoiceChat(VOICE_CHAT_FOLLOWME); break;
|
||||
case 10: PlayVoiceChat(VOICE_CHAT_LOOKHERE); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//For End of Combat Round
|
||||
void DoCombatCry()
|
||||
{
|
||||
if (GetHasEffect(EFFECT_TYPE_FRIGHTENED))
|
||||
{
|
||||
if (d100()<=CombatCryChance)
|
||||
{
|
||||
if (HasSpoken()) return;
|
||||
if ((GetRacialType(OBJECT_SELF) == RACIAL_TYPE_UNDEAD)&&(d100()<=CustomUndeadChance))
|
||||
switch (d6()) //Turned undead :)
|
||||
{
|
||||
case 1 : ActionSpeakString(COLOR_YELLOW+"It Burns! It Burns!",TALKVOLUME_TALK); break;
|
||||
case 2 : ActionSpeakString(COLOR_YELLOW+"Cursed Light!",TALKVOLUME_TALK); break;
|
||||
case 3 : ActionSpeakString(COLOR_YELLOW+"Your faith is weak, I can feel your fear...",TALKVOLUME_TALK); break;
|
||||
case 4 : ActionSpeakString(COLOR_YELLOW+"AAAIIIEEE!!!",TALKVOLUME_TALK); break;
|
||||
case 5 : ActionSpeakString(COLOR_YELLOW+"NOOO!!!",TALKVOLUME_TALK); break;
|
||||
case 6 : ActionSpeakString(COLOR_YELLOW+"It Burns!",TALKVOLUME_TALK); break;
|
||||
}
|
||||
else switch (d6())
|
||||
{
|
||||
case 1: PlayVoiceChat(VOICE_CHAT_FLEE); break;
|
||||
case 2: PlayVoiceChat(VOICE_CHAT_HELP); break;
|
||||
case 3: PlayVoiceChat(VOICE_CHAT_GUARDME); break;
|
||||
case 4: PlayVoiceChat(VOICE_CHAT_CUSS); break;
|
||||
case 5: PlayVoiceChat(VOICE_CHAT_BADIDEA); break;
|
||||
case 6: PlayVoiceChat(VOICE_CHAT_NEARDEATH); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (d100()<=CombatCryChance)
|
||||
{
|
||||
if (HasSpoken()) return;
|
||||
if ((GetRacialType(OBJECT_SELF) == RACIAL_TYPE_UNDEAD)&&(d100()<=CustomUndeadChance))
|
||||
switch (d6())
|
||||
{
|
||||
DoUndeadChatter();
|
||||
}
|
||||
else switch (d6())
|
||||
{
|
||||
case 1: PlayVoiceChat(VOICE_CHAT_BATTLECRY1); break;
|
||||
case 2: PlayVoiceChat(VOICE_CHAT_BATTLECRY2); break;
|
||||
case 3: PlayVoiceChat(VOICE_CHAT_BATTLECRY3); break;
|
||||
case 4: PlayVoiceChat(VOICE_CHAT_LAUGH); break;
|
||||
case 5: PlayVoiceChat(VOICE_CHAT_TAUNT); break;
|
||||
case 6: PlayVoiceChat(VOICE_CHAT_THREATEN); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//For Creature Death
|
||||
void DoDeathCry()
|
||||
{
|
||||
if (d100()<=DeathCryChance)
|
||||
{
|
||||
if (HasSpoken()) return;
|
||||
if ((GetRacialType(OBJECT_SELF) == RACIAL_TYPE_UNDEAD)&&(d100()<=CustomUndeadChance))
|
||||
switch (d6())
|
||||
{
|
||||
case 1 : ActionSpeakString(COLOR_RED+"Dead by dawn! Dead by dawn!",TALKVOLUME_TALK); break;
|
||||
case 2 : ActionSpeakString(COLOR_RED+"Death is only the beginning!",TALKVOLUME_TALK); break;
|
||||
case 3 : ActionSpeakString(COLOR_RED+"Darkness take me...",TALKVOLUME_TALK); break;
|
||||
case 4 : ActionSpeakString(COLOR_RED+"Free at last...",TALKVOLUME_TALK); break;
|
||||
case 5 : ActionSpeakString(COLOR_RED+"Time to die...",TALKVOLUME_TALK); break;
|
||||
case 6 : ActionSpeakString(COLOR_RED+"Thank you...",TALKVOLUME_TALK); break;
|
||||
} // "No more tears..."
|
||||
else switch (d6())
|
||||
{
|
||||
case 1: PlayVoiceChat(VOICE_CHAT_CUSS); break;
|
||||
case 2: PlayVoiceChat(VOICE_CHAT_DEATH); break;
|
||||
case 3: PlayVoiceChat(VOICE_CHAT_NEARDEATH); break;
|
||||
case 4: PlayVoiceChat(VOICE_CHAT_GOODBYE); break;
|
||||
case 5: PlayVoiceChat(VOICE_CHAT_LAUGH); break;
|
||||
case 6: PlayVoiceChat(VOICE_CHAT_HEALME); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//void main (){}
|
200
_module/nss/_inc_livingdead_.nss
Normal file
200
_module/nss/_inc_livingdead_.nss
Normal file
@@ -0,0 +1,200 @@
|
||||
const float fUnlifespan = 300.0;
|
||||
|
||||
string SpawnOf(object oSpawnKiller = OBJECT_INVALID)
|
||||
{
|
||||
string sSpawn = "";
|
||||
string sKiller = GetName(oSpawnKiller, FALSE);
|
||||
object oLeft = GetItemInSlot(INVENTORY_SLOT_LEFTHAND,oSpawnKiller);
|
||||
object oRight = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oSpawnKiller);
|
||||
string sLeftTag = GetTag(oLeft);
|
||||
string sRightTag = GetTag(oRight);
|
||||
if (!(GetStringRight(sKiller, 6) ==" Spawn") ||
|
||||
!(GetStringRight(sKiller, 6) ==" Rat"))
|
||||
if ((GetIsPC(GetMaster(oSpawnKiller))||(GetIsPC(oSpawnKiller))))
|
||||
{
|
||||
if ((FindSubString(sKiller, "Morg")>-1)||
|
||||
(sRightTag=="vampirespawner")||
|
||||
(sLeftTag=="vampirespawner")) sSpawn = "namechspawn";
|
||||
/* // No Vampires on Athas
|
||||
if ((FindSubString(sKiller, "Vampire")>-1)||(sRightTag=="vampirespawner")||(sLeftTag=="vampirespawner"))
|
||||
{
|
||||
if (GetGender(OBJECT_SELF)==GENDER_FEMALE) sSpawn = "vampirespawn_f";
|
||||
else sSpawn = "vampirespawn_m";
|
||||
} */
|
||||
else if ((FindSubString(sKiller, "Tyrantfog")>-1)||(sRightTag=="tyrantfogspawner")) sSpawn = "zombiespawn";
|
||||
else if (FindSubString(sKiller, "Ghoul")>-1) sSpawn = "ghoulspawn";
|
||||
else if (FindSubString(sKiller, "Ghast")>-1) sSpawn = "ghoulspawn";
|
||||
else if ((FindSubString(sKiller, "Shadow")>-1)||(sRightTag=="shadowspawner")) sSpawn = "shadowspawn";
|
||||
else if (FindSubString(sKiller, "Spectre")>-1) sSpawn = "spectrespawn";
|
||||
else if (FindSubString(sKiller, "Wraith")>-1) sSpawn = "wraithspawn";
|
||||
else if ((FindSubString(sKiller, "Wight")>-1)||(sRightTag=="wightspawner")) sSpawn = "wightspawn";
|
||||
else if (FindSubString(sKiller, "Crypt Chanter")>-1) sSpawn = "wraithspawn";
|
||||
else if (FindSubString(sKiller, "Bleakborn")>-1) sSpawn = "zombiespawn";
|
||||
else if (FindSubString(sKiller, "Bodak")>-1) sSpawn = "zombiespawn";
|
||||
else if (FindSubString(sKiller, "T'liz")>-1) sSpawn = "namechspawn";
|
||||
else if ((FindSubString(sKiller, "Meorty")>-1) ||
|
||||
(FindSubString(sKiller, "Amithrang")>-1)) sSpawn = "namechspawn";
|
||||
}
|
||||
else // Monster Killer
|
||||
{
|
||||
if (FindSubString(sKiller, "Tyrantfog")>-1) sSpawn = "zombiespawn";
|
||||
else if (FindSubString(sKiller, "Ghast")>-1) sSpawn = "ghoulspawn";
|
||||
else if (FindSubString(sKiller, "Ghoul")>-1) sSpawn = "ghoulspawn";
|
||||
else if (((FindSubString(sKiller, "Meorty")>-1) ||
|
||||
(FindSubString(sKiller, "Amithrang")>-1))) sSpawn = "namechspawn";
|
||||
else if (FindSubString(sKiller, "Shadow")>-1) sSpawn = "shadowspawn";
|
||||
else if (FindSubString(sKiller, "Spectre")>-1) sSpawn = "spectrespawn";
|
||||
else if (FindSubString(sKiller, "Crypt Chanter")>-1) sSpawn = "wraithspawn";
|
||||
else if (FindSubString(sKiller, "Bleakborn")>-1) sSpawn = "zombiespawn";
|
||||
else if (FindSubString(sKiller, "Bodak")>-1) sSpawn = "zombiespawn";
|
||||
else if (FindSubString(sKiller, "T'liz")>-1) sSpawn = "namechspawn";
|
||||
else if ((FindSubString(sKiller, "Morg")>-1)||
|
||||
(sRightTag=="vampirespawner")||
|
||||
(sLeftTag=="vampirespawner")) sSpawn = "namechspawn";
|
||||
/* //No Vampires on Athas
|
||||
{
|
||||
if (GetGender(OBJECT_SELF)==GENDER_FEMALE) sSpawn = "vampirespawn_f";
|
||||
else sSpawn = "vampirespawn_m";
|
||||
}*/
|
||||
else if (FindSubString(sKiller, "Wight")>-1) sSpawn = "wightspawn";
|
||||
if (FindSubString(sKiller, "Wraith")>-1) sSpawn = "wraithspawn";
|
||||
}
|
||||
return sSpawn;
|
||||
}
|
||||
|
||||
int ShadeType(object oShadeKiller = OBJECT_INVALID)
|
||||
{
|
||||
int iShade = 0;
|
||||
string sSpawn = "";
|
||||
string sKiller = GetName(oShadeKiller);
|
||||
object oRight = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oShadeKiller);
|
||||
string sRightTag = GetTag(oRight);
|
||||
if ((FindSubString(sKiller, "Shadow")>-1)||(sRightTag=="shadowspawner")) iShade = 1;
|
||||
else if (FindSubString(sKiller, "Spectre")>-1) iShade = 2;
|
||||
if (FindSubString(sKiller, "Wraith")>-1) iShade = 3;
|
||||
return iShade;
|
||||
}
|
||||
|
||||
int IsSpawnable(int iSpawnRace)
|
||||
{
|
||||
int iSpawnable = 0;
|
||||
if ((iSpawnRace == RACIAL_TYPE_ANIMAL)||
|
||||
(iSpawnRace == RACIAL_TYPE_BEAST)||
|
||||
(iSpawnRace == RACIAL_TYPE_MAGICAL_BEAST)||
|
||||
(iSpawnRace == RACIAL_TYPE_SHAPECHANGER)||
|
||||
(iSpawnRace == RACIAL_TYPE_VERMIN)||
|
||||
(iSpawnRace == RACIAL_TYPE_ABERRATION)||
|
||||
(iSpawnRace == RACIAL_TYPE_FEY)||
|
||||
(iSpawnRace == RACIAL_TYPE_GIANT)||
|
||||
(iSpawnRace == RACIAL_TYPE_HUMANOID_GOBLINOID)||
|
||||
(iSpawnRace == RACIAL_TYPE_HUMANOID_MONSTROUS)||
|
||||
(iSpawnRace == RACIAL_TYPE_HUMANOID_ORC)||
|
||||
(iSpawnRace == RACIAL_TYPE_HUMANOID_REPTILIAN)||
|
||||
(iSpawnRace == RACIAL_TYPE_DRAGON)||
|
||||
(iSpawnRace == RACIAL_TYPE_DWARF)||
|
||||
(iSpawnRace == RACIAL_TYPE_ELF)||
|
||||
(iSpawnRace == RACIAL_TYPE_GNOME)||
|
||||
(iSpawnRace == RACIAL_TYPE_HALFELF)||
|
||||
(iSpawnRace == RACIAL_TYPE_HALFLING)||
|
||||
(iSpawnRace == RACIAL_TYPE_HUMAN)||
|
||||
(iSpawnRace == RACIAL_TYPE_HALFORC))
|
||||
iSpawnable = 1;
|
||||
return iSpawnable;
|
||||
}
|
||||
|
||||
int IsNonHuman(int iSpawnRace)
|
||||
{
|
||||
int iSpawnable = 0;
|
||||
if ((iSpawnRace == RACIAL_TYPE_ANIMAL)||
|
||||
(iSpawnRace == RACIAL_TYPE_BEAST)||
|
||||
(iSpawnRace == RACIAL_TYPE_DRAGON)||
|
||||
(iSpawnRace == RACIAL_TYPE_MAGICAL_BEAST)||
|
||||
(iSpawnRace == RACIAL_TYPE_VERMIN)||
|
||||
(iSpawnRace == RACIAL_TYPE_ABERRATION)||
|
||||
(iSpawnRace == RACIAL_TYPE_FEY)||
|
||||
(iSpawnRace == RACIAL_TYPE_GIANT) ||
|
||||
(iSpawnRace == RACIAL_TYPE_HUMANOID_GOBLINOID)||
|
||||
(iSpawnRace == RACIAL_TYPE_HUMANOID_MONSTROUS)||
|
||||
(iSpawnRace == RACIAL_TYPE_HUMANOID_ORC)||
|
||||
(iSpawnRace == RACIAL_TYPE_HUMANOID_REPTILIAN))
|
||||
iSpawnable = 1;
|
||||
return iSpawnable;
|
||||
}
|
||||
|
||||
int UndeadCheck(object oMyKiller)
|
||||
{
|
||||
int iPassed = 0;
|
||||
int iSpawnVFX = VFX_FNF_SUMMON_UNDEAD;
|
||||
object oMyKiller = GetLastKiller();
|
||||
int iRace = GetRacialType(OBJECT_SELF);
|
||||
int iKillerRace = GetRacialType(oMyKiller);
|
||||
int iKillerUndeadClass = GetLevelByClass(CLASS_TYPE_UNDEAD, oMyKiller);
|
||||
object oLeft = GetItemInSlot(INVENTORY_SLOT_LEFTHAND,oMyKiller);
|
||||
object oRight = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oMyKiller);
|
||||
string sLeftTag = GetTag(oLeft);
|
||||
string sRightTag = GetTag(oRight);
|
||||
if ((iKillerRace==RACIAL_TYPE_UNDEAD)
|
||||
||(iKillerUndeadClass>0)
|
||||
||(sRightTag=="tyrantfogspawner")
|
||||
||(sRightTag=="shadowspawner")
|
||||
||(sRightTag=="CR_SLAM_PSISHAD1")
|
||||
||(sLeftTag=="CR_SLAM_PSISHAD1")
|
||||
||(sRightTag=="vampirespawner")
|
||||
||(sLeftTag=="vampirespawner"))
|
||||
if (IsSpawnable(iRace))
|
||||
{
|
||||
string sSpawnStr = SpawnOf(oMyKiller);
|
||||
if (sSpawnStr != "")
|
||||
{
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT,EffectVisualEffect(iSpawnVFX), OBJECT_SELF);
|
||||
object oSpawn = CreateObject(OBJECT_TYPE_CREATURE, sSpawnStr, GetLocation(OBJECT_SELF));
|
||||
if (GetIsObjectValid(oSpawn)) iPassed = 1;
|
||||
SetPortraitId(oSpawn, GetPortraitId(OBJECT_SELF));
|
||||
if (GetIsPC(GetMaster(oMyKiller))||(GetIsPC(oMyKiller)))
|
||||
{
|
||||
SetName(oSpawn,GetName(OBJECT_SELF,FALSE)+" "+GetName(oSpawn,TRUE));
|
||||
if (GetIsObjectValid(GetMaster(oMyKiller)))
|
||||
AddHenchman(GetMaster(oMyKiller), oSpawn);
|
||||
else AddHenchman(oMyKiller, oSpawn);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetName(oSpawn,GetName(OBJECT_SELF,FALSE)+" "+GetName(oSpawn,TRUE));
|
||||
//if (FindSubString(GetName(OBJECT_SELF)," Spawn")==-1) SetName(GetName(OBJECT_SELF)+ " Spawn");
|
||||
ChangeFaction(oSpawn,oMyKiller);
|
||||
}
|
||||
int iShadeNum = 0;
|
||||
if (IsNonHuman(iRace))
|
||||
{
|
||||
SetCreatureAppearanceType(oSpawn,GetAppearanceType(OBJECT_SELF));
|
||||
iShadeNum = ShadeType(oMyKiller);
|
||||
switch (iShadeNum)
|
||||
{
|
||||
case 1: //dark shadows
|
||||
ApplyEffectToObject(DURATION_TYPE_PERMANENT,SupernaturalEffect(EffectVisualEffect(VFX_DUR_PROT_SHADOW_ARMOR)),oSpawn,7.0);
|
||||
ApplyEffectToObject(DURATION_TYPE_PERMANENT,SupernaturalEffect(EffectVisualEffect(VFX_DUR_GHOST_TRANSPARENT)),oSpawn,7.0);
|
||||
break;
|
||||
case 2: //grey spectre
|
||||
ApplyEffectToObject(DURATION_TYPE_PERMANENT,SupernaturalEffect(EffectVisualEffect(VFX_DUR_GHOST_TRANSPARENT)),oSpawn,7.0);
|
||||
break;
|
||||
case 3: //light wraith
|
||||
ApplyEffectToObject(DURATION_TYPE_PERMANENT,SupernaturalEffect(EffectVisualEffect(VFX_DUR_GLOW_GREY)),oSpawn,7.0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (iShadeNum>0) //Fly off
|
||||
{
|
||||
DelayCommand(fUnlifespan-1.5,ApplyEffectToObject(DURATION_TYPE_PERMANENT,EffectDisappear(), oSpawn));
|
||||
DestroyObject(oSpawn, fUnlifespan);
|
||||
}
|
||||
else // Decay and Disintegrate
|
||||
{
|
||||
DelayCommand(fUnlifespan-1.5,ApplyEffectToObject(DURATION_TYPE_INSTANT,EffectVisualEffect(VFX_IMP_DEATH), oSpawn));
|
||||
DestroyObject(oSpawn, fUnlifespan);
|
||||
}
|
||||
}
|
||||
}
|
||||
return iPassed;
|
||||
}
|
||||
|
||||
//void main() {}
|
30
_module/nss/journal_db_name.nss
Normal file
30
_module/nss/journal_db_name.nss
Normal file
@@ -0,0 +1,30 @@
|
||||
//::///////////////////////////////////////////////
|
||||
//:: Journal Database Naming
|
||||
//:: journal_db_name
|
||||
//:://////////////////////////////////////////////
|
||||
/*
|
||||
|
||||
*/
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Constants
|
||||
//:://////////////////////////////////////////////
|
||||
|
||||
// the variable strJournalDatabaseName indicates the campaign
|
||||
// database to which the journal information will be written
|
||||
// set this value to the name that you wish to use.
|
||||
const string strJournalDatabaseName = "JournalDatabase";
|
||||
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Method: dhGetJournalDatabaseName
|
||||
//:: Created By: Dauvis
|
||||
//:: Created On: 7/13/03
|
||||
//::
|
||||
//:: This function will return the campaign name for the
|
||||
//:: the journal. To control to where the player's journal
|
||||
//:: information will be stored, change this function.
|
||||
//:://////////////////////////////////////////////
|
||||
string dhGetJournalDatabaseName(object oPlayer)
|
||||
{
|
||||
return strJournalDatabaseName;
|
||||
}
|
||||
|
22
_module/nss/journal_gnrc_oce.nss
Normal file
22
_module/nss/journal_gnrc_oce.nss
Normal file
@@ -0,0 +1,22 @@
|
||||
//::///////////////////////////////////////////////
|
||||
//:: Generic OnClientEnter
|
||||
//:: journal_gnrc_oce
|
||||
//:://////////////////////////////////////////////
|
||||
/*
|
||||
|
||||
*/
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Method: main
|
||||
//:: Created By: Dauvis
|
||||
//:: Created On: 6/29/03
|
||||
//::
|
||||
//:: This is a generic OnClientEnter script for the module.
|
||||
//:: This script just calls the appropriate journal
|
||||
//:: system method.
|
||||
//:://////////////////////////////////////////////
|
||||
#include "journal_include"
|
||||
|
||||
void main()
|
||||
{
|
||||
dhLoadJournalQuestStates(GetEnteringObject());
|
||||
}
|
475
_module/nss/journal_include.nss
Normal file
475
_module/nss/journal_include.nss
Normal file
@@ -0,0 +1,475 @@
|
||||
//::///////////////////////////////////////////////
|
||||
//:: Generic Journal Methods
|
||||
//:: journal_include
|
||||
//:://////////////////////////////////////////////
|
||||
/*
|
||||
|
||||
*/
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Constants
|
||||
//:://////////////////////////////////////////////
|
||||
|
||||
// The bHideFinishedQuests boolean variable controls if
|
||||
// completed quests are loaded into the journal when a
|
||||
// player logs back in. If set to TRUE, journal entries
|
||||
// will not be added. Otherwise, they will be loaded.
|
||||
const int bHideFinishedQuests = FALSE;
|
||||
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Method: dhJournalModuleLoad
|
||||
//:: Created By: Dauvis
|
||||
//:: Created On: 6/29/03
|
||||
//:: Modified By: Dauvis
|
||||
//:: Modified On: 7/3/03
|
||||
//::
|
||||
//:: This funciton is currently obsolete but is included
|
||||
//:: for backward compatibility.
|
||||
//:://////////////////////////////////////////////
|
||||
void dhJournalModuleLoad()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
#include "journal_db_name"
|
||||
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Method: dhAddJournalQuestEntry
|
||||
//:: Created By: Dauvis
|
||||
//:: Created On: 6/29/03
|
||||
//::
|
||||
//:: This method is a replacement for the AddJournalQuestEntry
|
||||
//:: standard function. It operates identically to the standard
|
||||
//:: function except that it will perform actions necessary
|
||||
//:: to give a persistant store to the journal entries.
|
||||
//:: The bMarkAsFinished arguments, which is not standard, is a
|
||||
//:: flag to indicate that the quest is finished. If there is
|
||||
//:: a way to figure this out from the module, I would like to know.
|
||||
//:://////////////////////////////////////////////
|
||||
void dhAddJournalQuestEntry(string strCategoryTag, int iEntryId, object oCreature,
|
||||
int bAllPartyMembers = TRUE, int bAllPlayers = FALSE, int bAllowOverrideHigher = FALSE,
|
||||
int bMarkAsFinished = FALSE)
|
||||
{
|
||||
object oPlayer;
|
||||
|
||||
// if bAllPlayers is true, make a call for each player
|
||||
if (bAllPlayers) {
|
||||
oPlayer = GetFirstPC();
|
||||
while (GetIsObjectValid(oPlayer)) {
|
||||
dhAddJournalQuestEntry(strCategoryTag, iEntryId, oPlayer, FALSE, FALSE,
|
||||
bAllowOverrideHigher, bMarkAsFinished);
|
||||
oPlayer = GetNextPC();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// if bAllPartyMembers is true, make a call for each player in the party
|
||||
if (bAllPartyMembers) {
|
||||
oPlayer = GetFirstFactionMember(oCreature, TRUE);
|
||||
while (GetIsObjectValid(oPlayer)) {
|
||||
dhAddJournalQuestEntry(strCategoryTag, iEntryId, oPlayer, FALSE, FALSE,
|
||||
bAllowOverrideHigher, bMarkAsFinished);
|
||||
oPlayer = GetNextFactionMember(oCreature, TRUE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// perform the standard function call
|
||||
AddJournalQuestEntry(strCategoryTag, iEntryId, oCreature, FALSE, FALSE, bAllowOverrideHigher);
|
||||
|
||||
// setup processing
|
||||
int iMaxIndex = GetLocalInt(oCreature, "iJournalMaxIndex");
|
||||
int bQuestFound = FALSE;
|
||||
int idx;
|
||||
string strTag;
|
||||
string strSerialized = "";
|
||||
int iState;
|
||||
|
||||
// loop through all of the quests loaded on the player
|
||||
// to find out if this is a new quest. build the
|
||||
// serialized string as we go.
|
||||
for (idx = 0; idx < iMaxIndex; idx++) {
|
||||
strTag = "strQuestTag" + IntToString(idx);
|
||||
strTag = GetLocalString(oCreature, strTag);
|
||||
|
||||
if (strTag == "") {
|
||||
continue;
|
||||
}
|
||||
if (strTag == strCategoryTag) {
|
||||
bQuestFound = TRUE;
|
||||
|
||||
// if marked as finished, clear the array element and do
|
||||
// not put it in the serialized string.
|
||||
if (bHideFinishedQuests && bMarkAsFinished) {
|
||||
strTag = "strQuestTag"+IntToString(idx);
|
||||
SetLocalString(oCreature, strTag, "");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
iState = GetLocalInt(oCreature, "NW_JOURNAL_ENTRY"+strTag);
|
||||
|
||||
strSerialized += strTag;
|
||||
strSerialized += ".";
|
||||
strSerialized += IntToString(iState);
|
||||
strSerialized += ".";
|
||||
}
|
||||
|
||||
// if quest wasn't found, add it to the serialized string
|
||||
// and record it on the PC. if marked as finished don't do
|
||||
// this
|
||||
if (!bQuestFound && (!bHideFinishedQuests || !bMarkAsFinished)) {
|
||||
strTag = "strQuestTag" + IntToString(iMaxIndex);
|
||||
SetLocalInt(oCreature, "iJournalMaxIndex", iMaxIndex+1);
|
||||
SetLocalString(oCreature, strTag, strCategoryTag);
|
||||
|
||||
iState = GetLocalInt(oCreature, "NW_JOURNAL_ENTRY"+strCategoryTag);
|
||||
strSerialized += strCategoryTag;
|
||||
strSerialized += ".";
|
||||
strSerialized += IntToString(iState);
|
||||
strSerialized += ".";
|
||||
}
|
||||
|
||||
// if marked as finished, set a flag in the database and add it to the
|
||||
// list of "completed" quests
|
||||
if (bMarkAsFinished) {
|
||||
strTag = "bQuestFinished_" + strCategoryTag;
|
||||
SetCampaignInt(dhGetJournalDatabaseName(oCreature), strTag, TRUE, oCreature);
|
||||
strTag = GetCampaignString(dhGetJournalDatabaseName(oCreature), "strCompletedQuests", oCreature);
|
||||
strTag += (strCategoryTag + ".");
|
||||
SetCampaignString(dhGetJournalDatabaseName(oCreature), "strCompletedQuests", strTag, oCreature);
|
||||
}
|
||||
|
||||
// store the serialized string
|
||||
SetCampaignString(dhGetJournalDatabaseName(oCreature), "strQuestStates", strSerialized, oCreature);
|
||||
}
|
||||
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Method: dhRemoveJournalQuestEntry
|
||||
//:: Created By: Dauvis
|
||||
//:: Created On: 6/29/03
|
||||
//::
|
||||
//:: This method is a replacement for the RemoveJournalQuestEntry
|
||||
//:: standard function. It operates identically to the standard
|
||||
//:: function except that it will perform actions necessary
|
||||
//:: to give a persistant store to the journal entries.
|
||||
//:: The bRemoveIfFinished argument, which is not standard, indicates
|
||||
//:: if the quest should be removed even if it was flagged as
|
||||
//:: finish. By default, finished quests will not be removed.
|
||||
//:://////////////////////////////////////////////
|
||||
void dhRemoveJournalQuestEntry(string strPlotId, object oCreature, int bAllPartyMembers = TRUE,
|
||||
int bAllPlayers = FALSE, int bRemoveIfFinished = FALSE)
|
||||
{
|
||||
object oPlayer;
|
||||
|
||||
// if bAllPlayers is true, make a call for each player
|
||||
if (bAllPlayers) {
|
||||
oPlayer = GetFirstPC();
|
||||
while (GetIsObjectValid(oPlayer)) {
|
||||
dhRemoveJournalQuestEntry(strPlotId, oCreature, FALSE, FALSE, bRemoveIfFinished);
|
||||
oPlayer = GetNextPC();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// if bAllPartyMembers is true, make a call for each player in the party
|
||||
if (bAllPartyMembers) {
|
||||
oPlayer = GetFirstFactionMember(oCreature, TRUE);
|
||||
while (GetIsObjectValid(oPlayer)) {
|
||||
dhRemoveJournalQuestEntry(strPlotId, oCreature, FALSE, FALSE, bRemoveIfFinished);
|
||||
oPlayer = GetNextFactionMember(oCreature, TRUE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// perform the standard function call
|
||||
RemoveJournalQuestEntry(strPlotId, oCreature, FALSE, FALSE);
|
||||
|
||||
// setup processing
|
||||
int iMaxIndex = GetLocalInt(oCreature, "iJournalMaxIndex");
|
||||
int idx;
|
||||
string strTag;
|
||||
string strSerialized = "";
|
||||
int iState;
|
||||
|
||||
// loop through all of the quests loaded on the player
|
||||
// to find this quest and remove it. build the
|
||||
// serialized string as we go.
|
||||
for (idx = 0; idx < iMaxIndex; idx++) {
|
||||
strTag = "strQuestTag" + IntToString(idx);
|
||||
strTag = GetLocalString(oCreature, strTag);
|
||||
|
||||
if (strTag == "") {
|
||||
continue;
|
||||
}
|
||||
if (strTag == strPlotId) {
|
||||
strTag = "strQuestTag"+IntToString(idx);
|
||||
SetLocalString(oCreature, strTag, "");
|
||||
continue;
|
||||
}
|
||||
iState = GetLocalInt(oCreature, "NW_JOURNAL_ENTRY"+strTag);
|
||||
|
||||
strSerialized += strTag;
|
||||
strSerialized += ".";
|
||||
strSerialized += IntToString(iState);
|
||||
strSerialized += ".";
|
||||
}
|
||||
|
||||
// if the remove if finished flag is set, see if the quest has been
|
||||
// marked as finished and unset it if it is (Don't just set the flag
|
||||
// because it will create an unnecessary database entry).
|
||||
if (bRemoveIfFinished) {
|
||||
strTag = "bQuestFinished_" + strPlotId;
|
||||
iState = GetCampaignInt(dhGetJournalDatabaseName(oCreature), strTag, oCreature);
|
||||
if (iState) {
|
||||
SetCampaignInt(dhGetJournalDatabaseName(oCreature), strTag, FALSE, oCreature);
|
||||
}
|
||||
}
|
||||
|
||||
// store the serialized string
|
||||
SetCampaignString(dhGetJournalDatabaseName(oCreature), "strQuestStates", strSerialized, oCreature);
|
||||
}
|
||||
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Method: dhGetJournalQuestState
|
||||
//:: Created By: Dauvis
|
||||
//:: Created On: 6/29/03
|
||||
//::
|
||||
//:: This function will return the current state of the specified
|
||||
//:: quest. If there isn't such a quest on the player's list,
|
||||
//:: it will return 0. If the quest is marked as finished,
|
||||
//:: it will return -1. Otherwise, it will return the quest's
|
||||
//:: state.
|
||||
//:://////////////////////////////////////////////
|
||||
int dhGetJournalQuestState(string strPlotId, object oCreature)
|
||||
{
|
||||
// check the database to see if the flag is set.
|
||||
string strTag = "bQuestFinished_" + strPlotId;
|
||||
int bFlag = GetCampaignInt(dhGetJournalDatabaseName(oCreature), strTag, oCreature);
|
||||
if (bFlag) return -1;
|
||||
|
||||
// return the state stored on the player
|
||||
strTag = "NW_JOURNAL_ENTRY" + strPlotId;
|
||||
int iState = GetLocalInt(oCreature, strTag);
|
||||
return iState;
|
||||
}
|
||||
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Method: dhNextToken
|
||||
//:: Created By: Dauvis
|
||||
//:: Created On: 6/29/03
|
||||
//::
|
||||
//:: This function is used in the parsing of a string into
|
||||
//:: tokens.
|
||||
//:://////////////////////////////////////////////
|
||||
string dhNextToken(string strSerialized, int iStart)
|
||||
{
|
||||
int idx = 0;
|
||||
string strChar;
|
||||
|
||||
if (GetStringLength(strSerialized) <= iStart) return "";
|
||||
|
||||
strChar = GetSubString(strSerialized, iStart+idx, 1);
|
||||
while (strChar != ".") {
|
||||
idx++;
|
||||
strChar = GetSubString(strSerialized, iStart+idx, 1);
|
||||
}
|
||||
return GetSubString(strSerialized, iStart, idx);
|
||||
}
|
||||
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Method: dhClearJournal
|
||||
//:: Created By: Dauvis
|
||||
//:: Created On: 6/29/03
|
||||
//::
|
||||
//:: This method clears the persistant information for
|
||||
//:: the player's journal. It is intended to be
|
||||
//:: called for new characters so that a new character
|
||||
//:: won't "inherit" values from a former character.
|
||||
//::
|
||||
//:: WARNING: if a character is recreated from one
|
||||
//:: that had a very large number of quests completed,
|
||||
//:: there will be a moment of lag as the information
|
||||
//:: is cleared.
|
||||
//:://////////////////////////////////////////////
|
||||
void dhClearJournal(object oPlayer)
|
||||
{
|
||||
string strCompleted;
|
||||
int iStart = 0;
|
||||
string strToken;
|
||||
string strTag;
|
||||
|
||||
strCompleted = GetCampaignString(dhGetJournalDatabaseName(oPlayer), "strCompletedQuests", oPlayer);
|
||||
while (TRUE) {
|
||||
strToken = dhNextToken(strCompleted, iStart);
|
||||
iStart += (GetStringLength(strToken) + 1);
|
||||
|
||||
if (strToken == "") break;
|
||||
|
||||
strTag = "bQuestFinished_" + strToken;
|
||||
SetCampaignInt(dhGetJournalDatabaseName(oPlayer), strTag, FALSE, oPlayer);
|
||||
}
|
||||
|
||||
// clear the pending quests and completed quests
|
||||
SetCampaignString(dhGetJournalDatabaseName(oPlayer), "strCompletedQuests", "", oPlayer);
|
||||
SetCampaignString(dhGetJournalDatabaseName(oPlayer), "strQuestStates", "", oPlayer);
|
||||
}
|
||||
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Method: dhLoadJournalQuestStates
|
||||
//:: Created By: Dauvis
|
||||
//:: Created On: 6/29/03
|
||||
//::
|
||||
//:: This method will load the quest states from the database
|
||||
//:: and store them on the player.
|
||||
//:://////////////////////////////////////////////
|
||||
void dhLoadJournalQuestStates(object oPlayer)
|
||||
{
|
||||
string strSerialized;
|
||||
int idx, iMaxIndex = 0;
|
||||
int iStart = 0;
|
||||
string strToken1;
|
||||
string strToken2;
|
||||
string strTag;
|
||||
|
||||
// error checking
|
||||
if (!GetIsPC(oPlayer)) return;
|
||||
|
||||
// check to make sure this is not a new character
|
||||
// because a player can recreate a character of the
|
||||
// same name
|
||||
if (GetXP(oPlayer) == 0) {
|
||||
dhClearJournal(oPlayer);
|
||||
return;
|
||||
}
|
||||
|
||||
// get serialized quest states
|
||||
strSerialized = GetCampaignString(dhGetJournalDatabaseName(oPlayer), "strQuestStates", oPlayer);
|
||||
while (TRUE) {
|
||||
strToken1 = dhNextToken(strSerialized, iStart);
|
||||
iStart += (GetStringLength(strToken1) + 1);
|
||||
strToken2 = dhNextToken(strSerialized, iStart);
|
||||
iStart += (GetStringLength(strToken2) + 1);
|
||||
|
||||
if (strToken1 == "" || strToken2 == "") {
|
||||
break;
|
||||
}
|
||||
|
||||
AddJournalQuestEntry(strToken1, StringToInt(strToken2), oPlayer, FALSE);
|
||||
strTag = "strQuestTag"+IntToString(iMaxIndex);
|
||||
SetLocalString(oPlayer, strTag, strToken1);
|
||||
iMaxIndex++;
|
||||
}
|
||||
|
||||
SetLocalInt(oPlayer, "iJournalMaxIndex", iMaxIndex+1);
|
||||
}
|
||||
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Method: dhGiveQuestItem
|
||||
//:: Created By: Dauvis
|
||||
//:: Created On: 7/3/03
|
||||
//::
|
||||
//:: This function is intended to be called in a death script for NPC but it can
|
||||
//:: be useful in other situations. When called, the function will check the
|
||||
//:: specified player to see if he is a specific state in a quest. If so,
|
||||
//:: it will award the specified item to him. This function return TRUE
|
||||
//:: if an item was awarded. It will return FALSE if the bAllParty flag is
|
||||
//:: set to TRUE.
|
||||
//::
|
||||
//:: strPlotId - the category tag for the quest
|
||||
//:: iReqState - the state at which the player must be at to receive the item
|
||||
//:: oPlayer - the player on which the check will be made
|
||||
//:: strResRef - the resource reference of the item to award
|
||||
//:: iQty - the quantity of items to give to the player
|
||||
//:: iNewState - the next state to which the quest will be changed. If this is
|
||||
//:: is set to -1, the quest's state will not be changed.
|
||||
//:: bAllParty - a flag to indicate if everyone in the player's party
|
||||
//:: should be checked and be awarded in addition to the player.
|
||||
//:: bMarkAsFinished - a flag to indicate that the quest should be marked as
|
||||
//:: finished if the quest state is changed by this function.
|
||||
//:://////////////////////////////////////////////
|
||||
int dhGiveQuestItem(string strPlotId, int iReqState, object oPlayer, string strResRef,
|
||||
int iQty = 1, int iNewState = -1, int bAllParty = FALSE, int bMarkAsFinished = FALSE)
|
||||
{
|
||||
object oCreature;
|
||||
|
||||
// if the bAllParty is true, apply this function to all players in
|
||||
// the party
|
||||
if (bAllParty) {
|
||||
oCreature = GetFirstFactionMember(oPlayer, TRUE);
|
||||
while (GetIsObjectValid(oCreature)) {
|
||||
dhGiveQuestItem(strPlotId, iReqState, oCreature, strResRef, iQty, iNewState);
|
||||
oCreature = GetNextFactionMember(oPlayer, TRUE);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// check to see if we are at the required state
|
||||
int iCurState = dhGetJournalQuestState(strPlotId, oPlayer);
|
||||
if (iCurState != iReqState) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// we are at the required state, award the item.
|
||||
CreateItemOnObject(strResRef, oPlayer, iQty);
|
||||
|
||||
// update the state if necessary
|
||||
if (iNewState != -1) {
|
||||
dhAddJournalQuestEntry(strPlotId, iNewState, oPlayer, FALSE, FALSE, FALSE, bMarkAsFinished);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Method: dhHideJournalQuestEntry
|
||||
//:: Created By: Dauvis
|
||||
//:: Created On: 7/13/03
|
||||
//:: Modified By: Dauvis
|
||||
//:: Modified On: 7/13/03
|
||||
//::
|
||||
//:: This function will remove a quest from the player's journal
|
||||
//:: if the quest has been marked as finished. Its purpose is to
|
||||
//:: provide a way to remove the journal entry from the journal if the
|
||||
//:: bHideJournalQuests flag is set to FALSE.
|
||||
//:://////////////////////////////////////////////
|
||||
void dhHideJournalQuestEntry(object oPlayer, string strPlotId)
|
||||
{
|
||||
int iMaxIndex = GetLocalInt(oPlayer, "iJournalMaxIndex");
|
||||
int idx;
|
||||
string strTag;
|
||||
string strSerialized = "";
|
||||
int iState;
|
||||
|
||||
// make sure the quest is marked as finished
|
||||
strTag = "bQuestFinished_" + strPlotId;
|
||||
int bFlag = GetCampaignInt(dhGetJournalDatabaseName(oPlayer), strTag, oPlayer);
|
||||
if (!bFlag) return;
|
||||
|
||||
// find the quest in the list and exclude from
|
||||
// serialize string
|
||||
for (idx = 0; idx < iMaxIndex; idx++) {
|
||||
strTag = "strQuestTag" + IntToString(idx);
|
||||
strTag = GetLocalString(oPlayer, strTag);
|
||||
|
||||
if (strTag == "") {
|
||||
continue;
|
||||
}
|
||||
if (strTag == strPlotId) {
|
||||
// clear the array element and do not put it in the serialized string.
|
||||
strTag = "strQuestTag"+IntToString(idx);
|
||||
SetLocalString(oPlayer, strTag, "");
|
||||
continue;
|
||||
}
|
||||
iState = GetLocalInt(oPlayer, "NW_JOURNAL_ENTRY"+strTag);
|
||||
|
||||
strSerialized += strTag;
|
||||
strSerialized += ".";
|
||||
strSerialized += IntToString(iState);
|
||||
strSerialized += ".";
|
||||
}
|
||||
|
||||
// save the new serialized string
|
||||
SetCampaignString(dhGetJournalDatabaseName(oPlayer), "strQuestStates", strSerialized, oPlayer);
|
||||
|
||||
// remove from journal for aestetic reasons
|
||||
RemoveJournalQuestEntry(strPlotId, oPlayer);
|
||||
}
|
479
_module/nss/pwfxp.nss
Normal file
479
_module/nss/pwfxp.nss
Normal file
@@ -0,0 +1,479 @@
|
||||
//PRC racial pack compatible PWFXP script
|
||||
//
|
||||
//PRC Version: 3.1e
|
||||
//Written by: Silvercloud (scl.vcs-online.com) & Ornedan
|
||||
// Modified by fluffyamoeba for 3.x versions of the PRC
|
||||
/*
|
||||
|
||||
changes: 2007-11-14
|
||||
|
||||
- pwfxp_prc_race now reads the 2da cache directly.
|
||||
|
||||
- the race LA is done entirely through this script. DO NOT set PRC_XP_USE_SIMPLE_LA
|
||||
or the XP penalty will be applied twice
|
||||
|
||||
- if using this with the supplied prc_pwondeath script, you don't need to make any
|
||||
changes to nw_c2_default7 (the OnDeath script)
|
||||
|
||||
- prc_racial_const no longer used
|
||||
|
||||
=================
|
||||
|
||||
Include added for prc races: pwfxp_prc_race, modify this file if you want to
|
||||
adjust ECLs (the subrace constants in pwfxp_def is removed).
|
||||
|
||||
Main function for determining ECL rewritten to hook into getECLMod.
|
||||
|
||||
package includes prc_racial_const for completeness, but you do not have to over-
|
||||
write the one in your world per se (for example if you have more races).
|
||||
|
||||
have fun,
|
||||
|
||||
Silvercloud
|
||||
|
||||
|
||||
//::///////////////////////////////////////////////
|
||||
//:: XP Distribution Script by Knat
|
||||
//:: pwfxp v1.70
|
||||
//:: Copyright (c) 2001 Bioware Corp.
|
||||
//:://////////////////////////////////////////////
|
||||
|
||||
|
||||
IMPORTANT: see pwfxp_def modifier definition script...
|
||||
|
||||
check this link in case you want to discuss this script:
|
||||
http://www.thefold.org/nuke/modules.php?name=Forums&file=viewforum&f=69
|
||||
|
||||
This is a more sophisticated XP distribution script geared towards PWs.
|
||||
It comes with two dozen XP modifiers to fine tune XP output and
|
||||
is losely based on the old but solid TTV XP script.
|
||||
|
||||
here is a small example of features, all modifiers are scalable:
|
||||
|
||||
- independent XP modifier for every single level. this breaks nwns linear
|
||||
XP progression and enables you to define your own progression function.
|
||||
you can give out fast xp early and let players slow down at any rate you want.
|
||||
or model your own progression function with the manipulation of two constants
|
||||
|
||||
- PCs suffer XP reduction if their level is not close enough to the average
|
||||
party level. level 1 grouping with level 10 is probably not a good idea...
|
||||
|
||||
- PCs suffer XP reduction if their level is not close enough to the CR of the killed MOB
|
||||
(both directions independent now)
|
||||
|
||||
- Adjustable & cached ECL modifiers, easy to sync with any subrace scripts
|
||||
|
||||
- Group bonus. groups receive a small XP bonus (or big, if you wish) to encourage teamplay
|
||||
|
||||
- Groupmembers need to be within minimum distance to the killed MOB if they want to receive XP
|
||||
|
||||
- associates get a share of the xp, but you can set a different divisor for each associate type
|
||||
e.g.: henchman soak up more XP then animal companions
|
||||
|
||||
- several counter exploit mechanisms included
|
||||
|
||||
- many more, see the constants...
|
||||
|
||||
- easy to add new modifiers..
|
||||
|
||||
all in all, this is pushing the nwn XP system more close to what you get in a MMORPG. You can
|
||||
make it very hard to level or easy as hell, with good control of group impact and flexible
|
||||
boundaries.
|
||||
|
||||
system went through extensive beta tests at www.thefold.org - thanks to all the great
|
||||
players and staff there...
|
||||
|
||||
------------------------------------------------------------------------------------------
|
||||
--- USAGE --- --- USAGE --- --- USAGE --- --- USAGE --- --- USAGE ------------------------
|
||||
------------------------------------------------------------------------------------------
|
||||
|
||||
just add the following line to the onDeath script of your creatures (default: nw_c2_default7):
|
||||
|
||||
ExecuteScript("pwfxp",OBJECT_SELF);
|
||||
|
||||
Don't forget to set the XP-Scale slider to 0 (module properties)
|
||||
|
||||
*note* if using your own prc_pwondeath script add this to that script instead.
|
||||
|
||||
ATTENTION: HOW TO REMOVE THE DOUBLE XP MESSAGE !
|
||||
|
||||
put this code above the pwfxp execution in your onDeath script
|
||||
|
||||
// safety mechanism in case creature kills itself
|
||||
if(GetLastKiller() == OBJECT_SELF) return;
|
||||
|
||||
put this code near the bottom of your onDeath script to remove the double-xp message
|
||||
thanks to spider661/Sotae for this catch...
|
||||
|
||||
// resurrect & self kill to bypass bioware xp message
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectResurrection(), OBJECT_SELF);
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(10000, DAMAGE_TYPE_MAGICAL, DAMAGE_POWER_PLUS_TWENTY), OBJECT_SELF);
|
||||
|
||||
------------------------------------------------------------------------------------------
|
||||
|
||||
changelog:
|
||||
|
||||
v1.7 update (3/2004)
|
||||
|
||||
- added PWFXP_MAXIMUM_XP constant due to user request...
|
||||
|
||||
v1.62 update (2/2004)
|
||||
|
||||
- fixed documentation error. using the wrong info could lead to divide by zero error
|
||||
|
||||
if you want to eliminate mob CR < PC-Level reduction:
|
||||
set PWFXP_CR_LESSTHAN_PCLEVEL_REDUCTION to PWFXP_CR_MAX and
|
||||
PWFXP_CR_LESSTHAN_PCLEVEL_NOXP to PWFXP_CR_MAX + 1
|
||||
|
||||
if you want to eliminate mob CR > PC-Level reduction:
|
||||
set PWFXP_CR_GREATERTHAN_PCLEVEL_REDUCTION to PWFXP_CR_MAX and
|
||||
PWFXP_CR_GREATERTHAN_PCLEVEL_NOXP to PWFXP_CR_MAX + 1
|
||||
|
||||
if you want to eliminate Average Party Level reduction:
|
||||
set PWFXP_APL_REDUCTION to 40 and
|
||||
PWFXP_APL_NOXP to 41
|
||||
|
||||
thanx to tribble for the catch
|
||||
|
||||
v1.61 update(1/2004)
|
||||
|
||||
- fixed minor naming convention error
|
||||
|
||||
v1.6 update(1/2004)
|
||||
|
||||
- improved XP divisor. you can now distinct between animal companion,
|
||||
familiar, dominated, summoned and henchman. you can set a different
|
||||
xp divisor for each of them. (default: henchman has max reduction impact followed
|
||||
by dominated, summoned, familiars, animal companion)
|
||||
|
||||
see PWFXP_XP_DIVISOR_* constants
|
||||
|
||||
- added PWFXP_USE_TOTAL_XP_TO_COMPUTE_PCLEVEL constant
|
||||
pc level gets computed based on the total XP instead of
|
||||
using GetLevelBy functions if set to TRUE. this way players ready to levelup
|
||||
can't bunker XP to gain better XP bonuses/modifiers.
|
||||
|
||||
- removed dumb debug fragments, no more svirfneblin invasions...
|
||||
thanks to Beowulf for the catch...
|
||||
|
||||
v1.5 update(12/2003)
|
||||
|
||||
- improved ECL modifier: added caching to decrease cpu use
|
||||
improved parser
|
||||
|
||||
v1.4 update(12/2003)
|
||||
|
||||
- removed constant PWFXP_CR_REDUCTION and PWFXP_CR_NOXP
|
||||
|
||||
- added 4 new constants instead to distinct between..
|
||||
PC-Level > CR
|
||||
PC-Level < CR
|
||||
..cases:
|
||||
|
||||
PWFXP_CR_LESSTHAN_PCLEVEL_REDUCTION
|
||||
PWFXP_CR_LESSTHAN_PCLEVEL_NOXP
|
||||
PWFXP_CR_GREATERTHAN_PCLEVEL_REDUCTION
|
||||
PWFXP_CR_GREATERTHAN_PCLEVEL_NOXP
|
||||
|
||||
- added PWFXP_USE_SETXP constant
|
||||
|
||||
- split the script up. now all constants are isolated in their own
|
||||
definiton file (pwfxp_def). easier to update that way...
|
||||
|
||||
v1.3 update (12/2003)
|
||||
|
||||
- added PWFXP_LEVEL_MODIFIERS. this removes the linear xp output... read more below
|
||||
|
||||
v1.2 update (10/2003)
|
||||
|
||||
- killer gets excluded from distance check now if he *is* a PC.
|
||||
he gets XP even if his spell kills something far away (e.g. long range spells,
|
||||
damage over time spells. maybe traps, not tested so far. this does not include NPCs)
|
||||
every other groupmember gets still checked for distance...
|
||||
[thanks to telstar for the report/request...]
|
||||
|
||||
v1.1 initial full release (10/2003)
|
||||
|
||||
- fine tuned and slightly optimized code
|
||||
- added debug toggle
|
||||
|
||||
v1.0 beta (8/2003):
|
||||
|
||||
- distance check should now work correctly
|
||||
|
||||
- minimum XP award (see new PWFXP_MINIMUM_XP constant)
|
||||
|
||||
- henchman, familiars, animal companions, summoned creatures and other NPCs in a player
|
||||
group now take away XP. see PWFXP_XP_DIVISOR_PC and PWFXP_XP_DIVISOR_NPC constants
|
||||
|
||||
- made it easier to manage ECL modifiers. see PWFXP_ECL_MODIFIERS string constant
|
||||
|
||||
*/
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Created By: LasCivious & Knat
|
||||
//:: Created On: 7/2003
|
||||
//:://////////////////////////////////////////////
|
||||
|
||||
#include "pwfxp_def"
|
||||
#include "pwfxp_prc_race"
|
||||
|
||||
|
||||
int PWFXP_GetLevel(object oPC)
|
||||
{
|
||||
// we need to use a derivation of the base xp formular to compute the
|
||||
// pc level based on total XP.
|
||||
//
|
||||
// base XP formula (x = pc level, t = total xp):
|
||||
//
|
||||
// t = x * (x-1) * 500
|
||||
//
|
||||
// need to use some base math..
|
||||
// transform for pq formula use (remove brackets with x inside and zero right side)
|
||||
//
|
||||
// x^2 - x - (t / 500) = 0
|
||||
//
|
||||
// use pq formula to solve it [ x^2 + px + q = 0, p = -1, q = -(t/500) ]...
|
||||
//
|
||||
// that's our new formular to get the level based on total xp:
|
||||
// level = 0.5 + sqrt(0.25 + (t/500))
|
||||
//
|
||||
if(PWFXP_USE_TOTAL_XP_TO_COMPUTE_PCLEVEL) // use total XP to compute PC level
|
||||
return FloatToInt(0.5 + sqrt(0.25 + ( IntToFloat(GetXP(oPC)) / 500 )));
|
||||
else // use total class level to compute PC level
|
||||
return GetLevelByPosition(1,oPC) + GetLevelByPosition(2,oPC) + GetLevelByPosition(3,oPC);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// see PWFXP_ECL_MODIFIERS constant description
|
||||
float PWFXP_GetECLModifier(object oPC)
|
||||
{
|
||||
// get current
|
||||
int nHD = GetHitDice(oPC);
|
||||
|
||||
// get last PC HD from cache
|
||||
int nECLHitDice = GetLocalInt(oPC,"PWFXP_ECL_HITDICE");
|
||||
|
||||
// last PC HD = current PC HD ? get ECL modifier from cache and return...
|
||||
if(nECLHitDice == nHD) return GetLocalFloat(oPC,"PWFXP_ECL_MODIFIER");
|
||||
|
||||
// recompute ECL modifier and cache it
|
||||
// this code section will run only in the case of two circumstances:
|
||||
//
|
||||
// 1. first time kill
|
||||
// 2. pc hitdice change (e.g. levelup)
|
||||
float fECLMod;
|
||||
fECLMod = IntToFloat(nHD) / (IntToFloat(nHD) + IntToFloat(GetECLMod(oPC)));
|
||||
SetLocalFloat(oPC,"PWFXP_ECL_MODIFIER", fECLMod);
|
||||
SetLocalInt(oPC,"PWFXP_ECL_HITDICE",nHD);
|
||||
return fECLMod;
|
||||
}
|
||||
// see PWFXP_LEVEL_MODIFIER constant description
|
||||
float PWFXP_GetLevelModifier(int nLevel)
|
||||
{
|
||||
return StringToFloat(GetSubString( PWFXP_LEVEL_MODIFIERS, (nLevel - 1) * 7, 6));
|
||||
}
|
||||
|
||||
// see PWFXP_APL_REDUCTION & PWFXP_APL_NOXP constant description
|
||||
float PWFXP_GetLevelDistanceModifier(float fLevelDistance)
|
||||
{
|
||||
if( fLevelDistance >= PWFXP_APL_NOXP )
|
||||
{
|
||||
// level distance greater than maximum allowed > no XP award at all
|
||||
return 0.0; // -100%
|
||||
}
|
||||
else if(fLevelDistance >= PWFXP_APL_REDUCTION)
|
||||
{
|
||||
// level distance greater than reduction limit ? reduce xp
|
||||
return 1 - ((fLevelDistance - PWFXP_APL_REDUCTION) * PWFXP_APL_MODIFIER);
|
||||
}
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
// see PWFXP_CR_LESSTHAN_PCLEVEL_REDUCTION, PWFXP_CR_LESSTHAN_PCLEVEL_NOXP
|
||||
// PWFXP_CR_GREATERTHAN_PCLEVEL_REDUCTION, PWFXP_CR_GREATERTHAN_PCLEVEL_NOXP
|
||||
// constant description
|
||||
float PWFXP_GetCRDistanceModifier(float fCRDistance)
|
||||
{
|
||||
// PC level > creature CR ?
|
||||
if(fCRDistance < 0.0)
|
||||
{
|
||||
fCRDistance = fabs(fCRDistance);
|
||||
if( fCRDistance >= PWFXP_CR_LESSTHAN_PCLEVEL_NOXP )
|
||||
{
|
||||
// level distance greater than maximum allowed > no XP award at all
|
||||
return 0.0; // -100%
|
||||
}
|
||||
else if(fCRDistance >= PWFXP_CR_LESSTHAN_PCLEVEL_REDUCTION)
|
||||
{
|
||||
// level distance greater than reduction limit ? reduce xp
|
||||
return 1 - ((fCRDistance - PWFXP_CR_LESSTHAN_PCLEVEL_REDUCTION) * PWFXP_CR_LESSTHAN_PCLEVEL_MODIFIER);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fCRDistance = fabs(fCRDistance);
|
||||
if( fCRDistance >= PWFXP_CR_GREATERTHAN_PCLEVEL_NOXP )
|
||||
{
|
||||
// level distance greater than maximum allowed > no XP award at all
|
||||
return 0.0; // -100%
|
||||
}
|
||||
else if(fCRDistance >= PWFXP_CR_GREATERTHAN_PCLEVEL_REDUCTION)
|
||||
{
|
||||
// level distance greater than reduction limit ? reduce xp
|
||||
return 1 - ((fCRDistance - PWFXP_CR_GREATERTHAN_PCLEVEL_REDUCTION) * PWFXP_CR_GREATERTHAN_PCLEVEL_MODIFIER);
|
||||
}
|
||||
}
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
// see PWFXP_KILLINGBLOW_MODIFIER constant description
|
||||
float PWFXP_GetMiscModifier(object oPC, object oKiller)
|
||||
{
|
||||
if(oPC == oKiller && PWFXP_KILLINGBLOW_MODIFIER != 0.0)
|
||||
{
|
||||
return 1 + PWFXP_KILLINGBLOW_MODIFIER;
|
||||
}
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
// see PWFXP_GROUPBONUS_MODIFIER constant description
|
||||
float PWFXP_GetGroupBonusModifier(int nGroupSize)
|
||||
{
|
||||
return 1 + ((nGroupSize-1) * PWFXP_GROUPBONUS_MODIFIER);
|
||||
}
|
||||
|
||||
// see PWFXP_XP_DIVISOR_* constants
|
||||
float PWFXP_GetAssociateDivisor(object oCreature)
|
||||
{
|
||||
switch(GetAssociateType(oCreature))
|
||||
{
|
||||
case ASSOCIATE_TYPE_ANIMALCOMPANION: return PWFXP_XP_DIVISOR_ANIMALCOMPANION;
|
||||
case ASSOCIATE_TYPE_DOMINATED: return PWFXP_XP_DIVISOR_DOMINATED;
|
||||
case ASSOCIATE_TYPE_FAMILIAR: return PWFXP_XP_DIVISOR_FAMILIAR;
|
||||
case ASSOCIATE_TYPE_HENCHMAN: return PWFXP_XP_DIVISOR_HENCHMAN;
|
||||
case ASSOCIATE_TYPE_SUMMONED: return PWFXP_XP_DIVISOR_SUMMONED;
|
||||
default: return PWFXP_XP_DIVISOR_UNKNOWN;
|
||||
}
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
// see PWFXP_MAXIMUM_DISTANCE_TO_GROUP constant description
|
||||
int PWFXP_CheckDistance(object oDead, object oGroupMbr)
|
||||
{
|
||||
return ( GetDistanceBetween(oDead, oGroupMbr) <= PWFXP_MAXIMUM_DISTANCE_TO_GROUP ) && ( GetArea(oDead) == GetArea(oGroupMbr) );
|
||||
}
|
||||
|
||||
// see PWFXP_USE_SETXP constant description
|
||||
void PWFXP_GiveXP(object oPC, int nXP)
|
||||
{
|
||||
if(PWFXP_USE_SETXP)
|
||||
SetXP(oPC, GetXP(oPC) + nXP);
|
||||
else
|
||||
GiveXPToCreature(oPC, nXP);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
object oDead = OBJECT_SELF;
|
||||
object oKiller = GetLastKiller();
|
||||
|
||||
// only continue if killer is valid and not from same faction...
|
||||
if ((oKiller==OBJECT_INVALID) || (GetFactionEqual(oKiller, oDead))) return;
|
||||
|
||||
// average party level, xp divisor
|
||||
float fAvgLevel, fDivisor;
|
||||
// groupsize, only PCs count
|
||||
int nGroupSize;
|
||||
|
||||
// get some basic group data like average PC level , PC group size, and XP divisor
|
||||
object oGroupMbr = GetFirstFactionMember(oKiller, FALSE);
|
||||
while(oGroupMbr != OBJECT_INVALID)
|
||||
{
|
||||
if( PWFXP_CheckDistance(oDead, oGroupMbr) || oGroupMbr == oKiller)
|
||||
{
|
||||
if(GetIsPC(oGroupMbr))
|
||||
{
|
||||
nGroupSize++;
|
||||
// add pc divisor
|
||||
fDivisor += PWFXP_XP_DIVISOR_PC;
|
||||
fAvgLevel += IntToFloat(PWFXP_GetLevel(oGroupMbr));
|
||||
}
|
||||
else
|
||||
fDivisor += PWFXP_GetAssociateDivisor(oGroupMbr); // add npc divisor
|
||||
}
|
||||
oGroupMbr = GetNextFactionMember(oKiller, FALSE);
|
||||
}
|
||||
|
||||
if(nGroupSize == 0)
|
||||
{
|
||||
// NPC (Minion) killed something without a PC (Master) near enough to get XP
|
||||
return;
|
||||
}
|
||||
|
||||
// calculate average partylevel
|
||||
fAvgLevel /= IntToFloat(nGroupSize);
|
||||
|
||||
// modifiers
|
||||
float fLevelModifier, fDistanceModifier, fCRModifier, fMiscModifier, fFinalModifier, fECLModifier, fGroupBonusModifier;
|
||||
// groupmember level
|
||||
float fMbrLevel;
|
||||
// get creature CR
|
||||
float fCR = GetChallengeRating(oDead);
|
||||
// reduce CR if greater then maximum CR cap
|
||||
if(fCR > PWFXP_CR_MAX) fCR = PWFXP_CR_MAX; // cap CR
|
||||
// multiply CR with global XP modifier
|
||||
float fModCR = fCR * PWFXP_GLOBAL_MODIFIER;
|
||||
|
||||
// calculate modifiers for each PC individually
|
||||
oGroupMbr = GetFirstFactionMember(oKiller, TRUE);
|
||||
while(oGroupMbr != OBJECT_INVALID)
|
||||
{
|
||||
fMbrLevel = IntToFloat(PWFXP_GetLevel(oGroupMbr));
|
||||
if( PWFXP_CheckDistance(oDead, oGroupMbr) || oGroupMbr == oKiller)
|
||||
{
|
||||
// get global level modifier
|
||||
fLevelModifier = PWFXP_GetLevelModifier(FloatToInt(fMbrLevel));
|
||||
// get PC-level distance to average group-level and compute modifier
|
||||
fDistanceModifier = PWFXP_GetLevelDistanceModifier(fabs(fAvgLevel - fMbrLevel));
|
||||
// get PC-level distance to CR of dead creature and compute modifier
|
||||
fCRModifier = PWFXP_GetCRDistanceModifier(fCR - fMbrLevel);
|
||||
// get misc modifiers (right now only 10% for killing blow dealer)
|
||||
fMiscModifier = PWFXP_GetMiscModifier(oGroupMbr, oKiller);
|
||||
// get group bonus modifier
|
||||
fGroupBonusModifier = PWFXP_GetGroupBonusModifier(nGroupSize);
|
||||
// get subrace ECL modifier
|
||||
fECLModifier = PWFXP_GetECLModifier(oGroupMbr);
|
||||
// calculate final modifier
|
||||
fFinalModifier = fLevelModifier * fDistanceModifier * fCRModifier * fMiscModifier * fGroupBonusModifier * fECLModifier;
|
||||
|
||||
// debug
|
||||
if(PWFXP_DEBUG)
|
||||
SendMessageToPC(oGroupMbr,GetName(oGroupMbr)+"'s XP Base: "+IntToString(FloatToInt(fModCR / fDivisor))+
|
||||
" / Modifiers: LVL [" + IntToString(FloatToInt((fLevelModifier-1)*100)) +
|
||||
"%] APD ["+IntToString(FloatToInt((fDistanceModifier-1)*100)) +
|
||||
"%] CRD ["+IntToString((fCR-fMbrLevel) < 0.0) + "/" + IntToString(FloatToInt((fCRModifier-1)*100))+
|
||||
"%] MSC ["+IntToString(FloatToInt((fMiscModifier-1)*100))+
|
||||
"%] GRP ["+IntToString(FloatToInt((fGroupBonusModifier-1)*100))+
|
||||
"%] ECL ["+IntToString(FloatToInt((fECLModifier-1)*100))+
|
||||
"%] GRS ["+IntToString(nGroupSize)+
|
||||
"] DIV ["+GetSubString(FloatToString(fDivisor),6,5) +
|
||||
"] FIN ["+IntToString(FloatToInt((fFinalModifier-1)*100))+
|
||||
"%]");
|
||||
|
||||
|
||||
int nXP = FloatToInt((fModCR / fDivisor) * fFinalModifier);
|
||||
|
||||
// award minimum/maximum xp if needed
|
||||
if(nXP < PWFXP_MINIMUM_XP)
|
||||
nXP = PWFXP_MINIMUM_XP;
|
||||
else if(nXP > PWFXP_MAXIMUM_XP)
|
||||
nXP = PWFXP_MAXIMUM_XP;
|
||||
|
||||
// misc checks for reasons the party member might not get XP would go here (eg. if they are dead)
|
||||
|
||||
if(nXP > 0) PWFXP_GiveXP(oGroupMbr, nXP);
|
||||
}
|
||||
oGroupMbr = GetNextFactionMember(oKiller, TRUE);
|
||||
}
|
||||
}
|
274
_module/nss/pwfxp_def.nss
Normal file
274
_module/nss/pwfxp_def.nss
Normal file
@@ -0,0 +1,274 @@
|
||||
//::///////////////////////////////////////////////
|
||||
//:: XP Distribution Script by Knat
|
||||
//:: pwfxp
|
||||
//:: Copyright (c) 2001 Bioware Corp.
|
||||
//:://////////////////////////////////////////////
|
||||
//void main(){}
|
||||
// note: default values are geared towards a LOW xp setting...
|
||||
// with easy leveling early (level 1-5) and very hard xp gain later on (lvl 30+)
|
||||
// all default values should be epic-level compatible
|
||||
|
||||
|
||||
// this will modify global xp output similar to the module xp-slider
|
||||
// higher value = more xp
|
||||
// PC needs to kill a combined CR of (PC-LEVEL * 1000) / PWFXP_GLOBAL_MODIFIER
|
||||
// on average to gain a level. use this as a rule of thumb and base to calculate
|
||||
// the more advanced modifiers
|
||||
//
|
||||
// e.g. a level 10 needs to kill 100 CR-10 mobs to level (aprox.) using default 10.0 global modifier
|
||||
// he will only need 50 CR-10 mobs if you set it to 20.0
|
||||
// setting this to 1000.0 = he only needs one CR-10 mob to level
|
||||
//
|
||||
// you can further scale the leveling progress more precisely with the PWFXP_LEVEL_MODIFIERS constant
|
||||
// just continue to read my comments...
|
||||
const float PWFXP_GLOBAL_MODIFIER = 10.0;
|
||||
|
||||
// displays one-line XP status info after each kill
|
||||
// useful while you fine tune the system.
|
||||
// and check the readme.txt in case you want to remove
|
||||
// the double-xp message from bioware...
|
||||
const int PWFXP_DEBUG = TRUE;
|
||||
|
||||
// NEW & experimental:
|
||||
// system will use the SetXP function instead of GiveXPToCreature if you set this to TRUE
|
||||
// this should bypass any "possible" bioware xp modification, like multiclass penalties.
|
||||
// i did not really test this so far, it's just some rumor i picked up from the
|
||||
// bioboards. choose whatever you feel better with...
|
||||
const int PWFXP_USE_SETXP = TRUE;
|
||||
|
||||
// NEW:
|
||||
// pc level gets computed based on the total XP instead of
|
||||
// using GetLevelBy functions if set to TRUE. this way players ready to levelup
|
||||
// can't bunker XP to gain better XP bonuses. a level 2 player with
|
||||
// 3500 total XP (thus, ready to levelup) gets considered
|
||||
// level 3 by the XP script if you set this switch to TRUE
|
||||
//
|
||||
// setting this to FALSE will use the old way of GetLevelByPosition.
|
||||
// i highly recommend the new way to counter XP (and probably more) exploits...
|
||||
const int PWFXP_USE_TOTAL_XP_TO_COMPUTE_PCLEVEL = TRUE;
|
||||
|
||||
// this is where you apply your subrace ECL modifiers
|
||||
// add them to the constant in this form "(ECL Modifier)-(Subrace)|...next|...etc"
|
||||
// COMMENTED OUT as it is no longer used in the calculations.
|
||||
//const string PWFXP_ECL_MODIFIERS = "1-ARCTIC DWARF|1-HALF OGRE|1-GITHYANKI|1-GITZERAI|1-OROG|1-GNOLL|1-LIZARDFOLK|1-AASIMAR|1-TIEFLING|1-HOBGOLBIN|1-GRAY DWARF|2-DROW MALE|2-DROW FEMALE|2-DEEP GNOME SVIRFNEBLIN|2-AVARIEL|2-MINOTAUR|2-BUGBEAR|2-FEY'RI|2-TANARUKK|3-OGRE|3-YUANTI PURE|3-AZER|4-PIXIE|4-ILLITHID|5-TROLL|6-RAKSHASHA";
|
||||
|
||||
// NEW:
|
||||
//
|
||||
// you can add a modifier to change XP output for every single level (including epic levels)
|
||||
// this also enables you to break the linear nature of NWNs default XP output.
|
||||
// you can change it to: logarithmic, exponential or any other non-linear
|
||||
// mathematical function using the PWFXP_LEVEL_MODIFIERS table
|
||||
//
|
||||
// you can make the first few levels an easy catch but make the last a pain to reach.... very flexible now
|
||||
//
|
||||
// default setting:
|
||||
//
|
||||
// level 1 = 1000% xp bonus
|
||||
// level 2 = 500% xp bonus
|
||||
// level 3 = 300% xp bonus
|
||||
// level 4 = 200% xp bonus
|
||||
// level 5 = 100% xp bonus
|
||||
//
|
||||
// level 6 - 10 = no xp change
|
||||
|
||||
// level 11 = -15% xp penalty
|
||||
// level 12 = -15%
|
||||
// level 13 = -20%
|
||||
// level 14 = -20%
|
||||
// level 15 = -25%
|
||||
// level 16 = -25%
|
||||
// level 17 = -30%
|
||||
// level 18 = -30%
|
||||
// level 19 = -35%
|
||||
// level 20 = -35%
|
||||
//
|
||||
// level 21 = -40% xp penalty
|
||||
// level 22 = -45%
|
||||
// level 23 = -50%
|
||||
// level 24 = -55%
|
||||
// level 25 = -60%
|
||||
// level 26 = -65%
|
||||
// level 27 = -70%
|
||||
// level 28 = -80%
|
||||
// level 29 = -90%
|
||||
//
|
||||
// level 30 = -91% xp penalty
|
||||
// level 31 = -91%
|
||||
// level 32 = -92%
|
||||
// level 33 = -92%
|
||||
// level 34 = -93%
|
||||
// level 35 = -93%
|
||||
// level 36 = -94%
|
||||
// level 37 = -94%
|
||||
// level 38 = -95%
|
||||
// level 39 = -96%
|
||||
//
|
||||
// these settings make it easy first but very tough at later levels.
|
||||
// the pc would need to kill 100 level 10 creatures to level from 10 to 11, but
|
||||
// several thousand CR 40 creatures to level from 39 to 40, with the above settings.
|
||||
// (not counting group bonus or other advanced modifiers)
|
||||
//
|
||||
// modifier explanation:
|
||||
//
|
||||
// a value of 1 (01.000) means no xp change.
|
||||
//
|
||||
// the actual xp bonus/penalty in % = (modifier - 1) * 100
|
||||
//
|
||||
// use value < 1.0 to reduce the xp
|
||||
// e.g. 00.500 = -50%
|
||||
// 00.010 = -99%
|
||||
// 00.001 = -99.9%
|
||||
//
|
||||
// attention: syntax !!
|
||||
// always pad with 0. each number must be 6 chars long
|
||||
// otherwise the parser will fail and your players get 0xp
|
||||
// i use very simplistic parsing to optimize cpu use...
|
||||
//
|
||||
// the first number modifies level 1, the last number level 40
|
||||
//
|
||||
// LEVEL-----01--|--02--|--03--|--04--|--05--|--06--|--07--|--08--|--09--|--10--|--11--|--12--|--13--|--14--|--15--|--16--|--17--|--18--|--19--|--20--|--21--|--22--|--23--|--24--|--25--|--26--|--27--|--28--|--29--|--30--|--31--|--32--|--33--|--34--|--35--|--36--|--37--|--38--|--39--|--40--|
|
||||
const string PWFXP_LEVEL_MODIFIERS = "11.000|06.000|04.000|01.000|01.000|01.000|01.000|01.000|01.000|01.000|00.850|00.850|00.800|00.800|00.750|00.750|00.700|00.700|00.650|00.650|00.600|00.550|00.500|00.450|00.400|00.350|00.300|00.200|00.100|00.090|00.090|00.080|00.080|00.070|00.070|00.060|00.060|00.050|00.040|00.040";
|
||||
|
||||
// small bonus for killing blow dealer
|
||||
const float PWFXP_KILLINGBLOW_MODIFIER = 1.5; // 0%
|
||||
|
||||
// PC level gets compared to the average party level.
|
||||
// APL = Average Party Level
|
||||
//
|
||||
//
|
||||
// attention: the below example was from version 1.1
|
||||
// most if not all constants have been changed (scalar for example is 100% now and thus fully linear)
|
||||
//
|
||||
// example uses below values
|
||||
// const float PWFXP_APL_REDUCTION = 2.0;
|
||||
// const float PWFXP_APL_NOXP = 4.0;
|
||||
// const float PWFXP_SCALAR = 0.5
|
||||
//
|
||||
// XP gets reduced if PC-level > APL + APL_REDUCTION
|
||||
// XP reduction is based on SCALAR, be careful if you change this
|
||||
// right now its 0 - 50% (scalar 0.5) for delta 2 (APL_REDUCTION) .. delta 4 (APL_NOXP)
|
||||
// delta = abs(APL - PC Level)
|
||||
// this means it will switch from 50% reduction to 100% reduction in one leap in case the PC level
|
||||
// is greater then APL + APL_NOXP.
|
||||
// i did this for a better granularity for the given default values but
|
||||
// you can freely change APL_REDUCTION and/or APL_NOXP. XP reduction gets auto-adjusted to the maximum
|
||||
// of SCALAR (50% default).
|
||||
//
|
||||
// XP gets reduced to zero if PC-level > APL + APL_NOXP
|
||||
//
|
||||
// Example (using default values):
|
||||
// PC A = level 7
|
||||
// PC B = level 3
|
||||
// PC C = level 1
|
||||
//
|
||||
// average party level (APL) = 3.66
|
||||
//
|
||||
// Distance PC A = abs(PClevel - AveragePartyLevel) = abs(7 - 3.66) = 3.34
|
||||
// PC-A has a final distance of 1.34 (3.34 - APL_REDUCTION)
|
||||
// XP reduction = (SCALAR / (APL_NOXP - APL_REDUCTION)) * 1.34 = (0.5 / 2) * 1.34 = 33.5% XP reduction
|
||||
//
|
||||
// Distance PC B = abs(PClevel - AveragePartyLevel) = abs(3 - 3.66) = 0.66
|
||||
// PC-A has a final distance of -1.34 (0.66 - APL_REDUCTION)
|
||||
// no XP reduction
|
||||
//
|
||||
// Distance PC C = abs(PClevel - AveragePartyLevel) = abs(1 - 3.66) = 2.66
|
||||
// PC-A has a final distanceof 0.66 (2.66 - APL_REDUCTION)
|
||||
// XP reduction = (SCALAR / (APL_NOXP - APL_REDUCTION)) * 0.66 = (0.5 / 2) * 0.66 = 16.5% XP reduction
|
||||
//
|
||||
// those PCs with the biggest impact to the average party level receive the biggest XP reduction
|
||||
// (in the above case PC A)
|
||||
//
|
||||
// set _REDUCTION to 40 and _NOXP to 41 if you don't want any APL reduction
|
||||
//
|
||||
// changed default to a bit less harsh values
|
||||
const float PWFXP_APL_REDUCTION = 3.0; // levels
|
||||
const float PWFXP_APL_NOXP = 6.0;
|
||||
|
||||
// NEW:
|
||||
// these 4 constants works like the APL constants above but it compares
|
||||
// PC level vs challenge rating of the dead creature
|
||||
//
|
||||
// you can distinct two different cases now:
|
||||
//
|
||||
// PC level > CR of the creature (CR + PWFXP_CR_LESSTHAN_PCLEVEL_REDUCTION)
|
||||
// PC level < CR of the creature (CR + PWFXP_CR_GREATERTHAN_PCLEVEL_REDUCTION)
|
||||
//
|
||||
// math is the same as the APL example above, just exchange
|
||||
// AveragePartyLevel with CR of dead creature and use
|
||||
// PWFXP_CR_*_PCLEVEL_REDUCTION and PWFXP_CR_*_PCLEVEL_NOXP as the constants
|
||||
//
|
||||
// set _REDUCTION to CR_MAX and _NOXP to CR_MAX+1 if you don't want any cr reduction
|
||||
//
|
||||
// reduction constants for PCs fighting mobs with a CR below their level
|
||||
const float PWFXP_CR_LESSTHAN_PCLEVEL_REDUCTION = 3.0;
|
||||
const float PWFXP_CR_LESSTHAN_PCLEVEL_NOXP = 10.0;
|
||||
|
||||
// note: default setting only penalize PCs if they try to kill something
|
||||
// that should be *impossible* for their level.
|
||||
// a 40 level epic PC will be able to kill CR 60 creatures without
|
||||
// penalty and a large low-level group of players will be able to
|
||||
// kill a much higher CR creature without penalty...(a group of lvl5 players killing
|
||||
// a CR 20 creature won't receive any penalty. penalty will start to kick in if they try
|
||||
// to kill a creature with a CR > 25
|
||||
// you can use this to counter low-level XP exploits. e.g. a level 40 player
|
||||
// could mangle a mob down to 1 HP. then a low level comes in and deals the final
|
||||
// blow -> classical xp exploit...
|
||||
// default settings make sure that nothing can get out of hand, but you can make
|
||||
// this harsher if you want (but keep in mind that creatures can have a higher
|
||||
// CR than the players maximum level, like CR 60)
|
||||
//
|
||||
// set _REDUCTION to CR_MAX and _NOXP to CR_MAX+1 if you don't want any cr reduction
|
||||
//
|
||||
// reduction constants for PCs fighting mobs with a CR above their level
|
||||
const float PWFXP_CR_GREATERTHAN_PCLEVEL_REDUCTION = 20.0;
|
||||
const float PWFXP_CR_GREATERTHAN_PCLEVEL_NOXP = 30.0;
|
||||
|
||||
// described above
|
||||
const float PWFXP_SCALAR = 1.0;
|
||||
|
||||
// maximum CR cap
|
||||
// this stops creatures with sky-high CRs from giving godly XP
|
||||
const float PWFXP_CR_MAX = 60.0;
|
||||
|
||||
// groups get a small xp bonus
|
||||
// formular is groupsize-1 * modifier
|
||||
// with a default value of 0.1 (10%) a party of 4 receives 30% XP bonus
|
||||
// this should encourage grouping
|
||||
// set it to 0.0 if you dont like that...
|
||||
const float PWFXP_GROUPBONUS_MODIFIER = 0.1;
|
||||
|
||||
// groub members need to be within this distance to the dead creature
|
||||
// if they want to get any XP during fights
|
||||
const float PWFXP_MAXIMUM_DISTANCE_TO_GROUP = 30.0; // meters
|
||||
|
||||
// safety mechanism
|
||||
// minimum XP for a kill
|
||||
const int PWFXP_MINIMUM_XP = 0;
|
||||
|
||||
// safety mechanism
|
||||
// maximum XP for a kill
|
||||
const int PWFXP_MAXIMUM_XP = 1000;
|
||||
|
||||
// UPDATED:
|
||||
// these constants determine how XP division works
|
||||
// you can now distinct between animal companion,
|
||||
// familiars, dominated, summoned and henchman. you can set a different
|
||||
// xp divisor for each of them. (default: henchman has max reduction impact followed
|
||||
// by dominated, summoned, familiars, animal companion)
|
||||
// e.g.: a group with two PCs + 1 FAMILIAR + 1 SUMMONED CREATURE
|
||||
// gets a total XP divisor of 2.5 (using default values).
|
||||
// if they kill a 1000XP mob, both PCs only receive 400 XP
|
||||
const float PWFXP_XP_DIVISOR_PC = 1.0;
|
||||
const float PWFXP_XP_DIVISOR_DOMINATED = 0.5;
|
||||
const float PWFXP_XP_DIVISOR_HENCHMAN = 0.5;
|
||||
const float PWFXP_XP_DIVISOR_SUMMONED = 0.3;
|
||||
const float PWFXP_XP_DIVISOR_ANIMALCOMPANION = 0.1;
|
||||
const float PWFXP_XP_DIVISOR_FAMILIAR = 0.1;
|
||||
// used in case i can't determine the associate type
|
||||
const float PWFXP_XP_DIVISOR_UNKNOWN = 0.5;
|
||||
|
||||
// don't change these
|
||||
float PWFXP_APL_MODIFIER = PWFXP_SCALAR / (PWFXP_APL_NOXP - PWFXP_APL_REDUCTION);
|
||||
float PWFXP_CR_LESSTHAN_PCLEVEL_MODIFIER = PWFXP_SCALAR / (PWFXP_CR_LESSTHAN_PCLEVEL_NOXP - PWFXP_CR_LESSTHAN_PCLEVEL_REDUCTION);
|
||||
float PWFXP_CR_GREATERTHAN_PCLEVEL_MODIFIER = PWFXP_SCALAR / (PWFXP_CR_GREATERTHAN_PCLEVEL_NOXP - PWFXP_CR_GREATERTHAN_PCLEVEL_REDUCTION);
|
||||
|
16
_module/nss/pwfxp_prc_race.nss
Normal file
16
_module/nss/pwfxp_prc_race.nss
Normal file
@@ -0,0 +1,16 @@
|
||||
// written by fluffyamoeba 09-07-06
|
||||
// actually gets the LA modifier, not ECL
|
||||
// gets the LA from ecl.2da (actually the 2da cache)
|
||||
// used to hand out XP adjusted for LA
|
||||
|
||||
int GetECLMod(object oCreature);
|
||||
|
||||
#include "inc_utility"
|
||||
|
||||
int GetECLMod(object oCreature)
|
||||
{
|
||||
int nRace = GetRacialType(oCreature); //note this is not MyPRCGetRacialType becuase we want to include subraces too
|
||||
int nLA = 0;
|
||||
nLA = StringToInt(Get2DACache("ECL", "LA", nRace));
|
||||
return nLA;
|
||||
}
|
@@ -448,7 +448,7 @@ void main()
|
||||
|
||||
// Check for randomizations.
|
||||
|
||||
RndBanditArmor(OBJECT_SELF);
|
||||
// RndBanditArmor(OBJECT_SELF);
|
||||
|
||||
ms_Nomenclature(OBJECT_SELF);
|
||||
|
||||
|
@@ -1,3 +1,5 @@
|
||||
#include "journal_include"
|
||||
|
||||
void GivePCWands(object oPC)
|
||||
{
|
||||
// items to be give to new players
|
||||
@@ -125,6 +127,8 @@ void main()
|
||||
{
|
||||
object oPC = GetEnteringObject();
|
||||
|
||||
dhLoadJournalQuestStates(GetEnteringObject());
|
||||
|
||||
// Make sure PC isn't set to Plot, for reasons
|
||||
SetPlotFlag(oPC, FALSE);
|
||||
|
||||
|
@@ -10,11 +10,18 @@
|
||||
|
||||
void RndBanditArmor(object oNPC)
|
||||
{
|
||||
// Makes sure any original armor isn't dropped as loot.
|
||||
SetDroppableFlag(GetItemInSlot(INVENTORY_SLOT_CHEST, OBJECT_SELF), 0);
|
||||
|
||||
//Randomizes Armor
|
||||
|
||||
//Randomizes Armor
|
||||
int nResult = d6(1);
|
||||
int nStackSize = 1; // Create 1 items;
|
||||
|
||||
object oArmor;
|
||||
|
||||
string sItem;
|
||||
|
||||
if (nResult == 1)
|
||||
{
|
||||
sItem = "NW_AARCL001";
|
||||
@@ -29,15 +36,30 @@ void RndBanditArmor(object oNPC)
|
||||
}
|
||||
else if(nResult ==4)
|
||||
{
|
||||
sItem = "NW_AARCL010";
|
||||
sItem = "NW_AARCL008";
|
||||
}
|
||||
else if(nResult == 5)
|
||||
{
|
||||
sItem = "NW_AARCL004";
|
||||
sItem = "NW_AARCL002";
|
||||
}
|
||||
else
|
||||
sItem = "NW_AARCL008";
|
||||
|
||||
DelayCommand(1.0f, ActionEquipItem(CreateItemOnObject(sItem), INVENTORY_SLOT_CHEST));
|
||||
}
|
||||
CreateItemOnObject(sItem, OBJECT_SELF, nStackSize);
|
||||
|
||||
// Loop the object's inventory and equip the first
|
||||
object oItem = GetFirstItemInInventory(OBJECT_SELF);
|
||||
while(GetIsObjectValid(oItem))
|
||||
{
|
||||
// Check if armor, of course
|
||||
if(GetBaseItemType(oItem) == BASE_ITEM_ARMOR)
|
||||
{
|
||||
// Equip it and stop the script
|
||||
DelayCommand(1.0f, ActionEquipItem(oItem, INVENTORY_SLOT_CHEST));
|
||||
return;
|
||||
}
|
||||
|
||||
oItem = GetNextItemInInventory(OBJECT_SELF);
|
||||
}
|
||||
|
||||
}
|
||||
|
77
_module/nss/shadow_touch.nss
Normal file
77
_module/nss/shadow_touch.nss
Normal file
@@ -0,0 +1,77 @@
|
||||
//::
|
||||
//:: A pnp version of the Shadows's STR damaging touch.
|
||||
//::
|
||||
//:: Modified by: DM Heatstroke 01-04-11
|
||||
//::
|
||||
|
||||
#include "NW_I0_SPELLS"
|
||||
#include "nw_i0_plot"
|
||||
|
||||
void DoStrDamage(object oTarget, object oCaster)
|
||||
{ //::
|
||||
//:: Intialize damage value & figure out which shadow we are dealing with
|
||||
//::
|
||||
int nHitDice = GetHitDice(oCaster);
|
||||
int nDam;
|
||||
if (1 == nHitDice)
|
||||
{
|
||||
nDam = 1; //Lesser Shadow
|
||||
}
|
||||
|
||||
else if (nHitDice >= 9)
|
||||
{
|
||||
nDam = d8(); //Greater Shadow
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
nDam = d6(); //Normal Shadow
|
||||
}
|
||||
|
||||
// Get Ability Damage
|
||||
effect eVis = EffectVisualEffect(VFX_IMP_REDUCE_ABILITY_SCORE);
|
||||
effect eStr = EffectAbilityDecrease(ABILITY_STRENGTH, nDam);
|
||||
eStr = SupernaturalEffect(eStr);
|
||||
|
||||
// Determine if they can die from ability loss
|
||||
int bKillEm = FALSE;
|
||||
if ( !GetIsPC(oTarget) || GetGameDifficulty() == GAME_DIFFICULTY_CORE_RULES
|
||||
|| GetGameDifficulty() == GAME_DIFFICULTY_DIFFICULT )
|
||||
bKillEm = TRUE;
|
||||
|
||||
// Shadow's touch has no save!
|
||||
int nStr = GetAbilityScore(oTarget, ABILITY_STRENGTH);
|
||||
if ( ( nStr - nDam ) < 3 && bKillEm )
|
||||
{
|
||||
effect eVis3 = EffectVisualEffect(VFX_IMP_DEATH);
|
||||
effect eHP2 = EffectDamage( 9999, DAMAGE_TYPE_MAGICAL , DAMAGE_POWER_PLUS_TWENTY);
|
||||
effect eDeath2 = EffectDeath();
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT,eVis3,oTarget);
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT,eDeath2,oTarget);
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT,eHP2,oTarget);
|
||||
|
||||
}
|
||||
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget); // Apply Viz
|
||||
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eStr, oTarget, 8640.0); // 24 "Athas Reborn" hours -DMH
|
||||
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
object oTarget = GetSpellTargetObject();
|
||||
object oCaster = OBJECT_SELF;
|
||||
|
||||
/* int bIsPoisoned = GetLocalInt(oTarget,"IsPoisoned");
|
||||
if ( bIsPoisoned )
|
||||
return; */
|
||||
|
||||
if ( GetIsImmune(oTarget,IMMUNITY_TYPE_ABILITY_DECREASE) )
|
||||
{
|
||||
SendMessageToPC(oTarget,"Immune to ability drain.");
|
||||
return;
|
||||
}
|
||||
|
||||
DelayCommand(0.1,DoStrDamage(oTarget,oCaster));
|
||||
|
||||
}
|
66
_module/nss/sparky_enc.nss
Normal file
66
_module/nss/sparky_enc.nss
Normal file
@@ -0,0 +1,66 @@
|
||||
// Sparky predefined encounters include
|
||||
// Created By: The Amethyst Dragon
|
||||
|
||||
// Add encounter variables to oArea based on the number entered as nTable.
|
||||
// 0 = blank
|
||||
void LoadEncounterVariables(object oArea, int nTable);
|
||||
void LoadEncounterVariables(object oArea, int nTable)
|
||||
{
|
||||
if (nTable < 1) { return; }
|
||||
if (GetIsObjectValid(oArea) != TRUE) { return; }
|
||||
|
||||
// Check for existing encounter variables (maximum of 10 encounters on an area)
|
||||
int nCheckNum = GetLocalInt(oArea, "NumEnc");
|
||||
if (nCheckNum < 1) nCheckNum = 0;
|
||||
if (nCheckNum >= 10) return;
|
||||
nCheckNum = nCheckNum + 1;
|
||||
string sEncNum = "encounter_";
|
||||
if (nCheckNum < 10) sEncNum = "encounter_0";
|
||||
sEncNum = sEncNum + IntToString(nCheckNum); // encounter numbers need to be incremented for the Spawner to read them correctly
|
||||
SetLocalInt(oArea, "NumEnc", nCheckNum);
|
||||
|
||||
// In this section is where you would record your predefined encounter variables.
|
||||
// The script adds them to areas as it is called on.
|
||||
//
|
||||
// For further information on how to format this information, you can check in
|
||||
// your NWN/docs/cep/sparky_spawner folder for the Aenea_Sparky_Docs.pdf file.
|
||||
//
|
||||
// A helpful Excel file is also included in that folder to aid in speeding up the
|
||||
// variable creation.
|
||||
switch (nTable)
|
||||
{
|
||||
|
||||
case 1: // Brigand Scout
|
||||
SetLocalString(oArea, sEncNum, "v2, day, 50, creature, ra_brigand001, 1, random, 1.0, 1, 1");
|
||||
break;
|
||||
|
||||
case 2: // Bandits
|
||||
SetLocalString(oArea, sEncNum, "v2, day, 50, creature, NW_BANDIT001, 2-4, random, 1.0, 1, 1");
|
||||
|
||||
case 3: // Brigands
|
||||
SetLocalString(oArea, sEncNum, "v2, day, 12.5, group, brigands");
|
||||
SetLocalString(oArea, "group_brigands_01", "creature, ra_brigand002, 1, wp: brigands, 1.0, 1, 1");
|
||||
SetLocalString(oArea, "group_brigands_02", "creature, ra_brigand001, 2-8, last, 5.0, 1, 1");
|
||||
break;
|
||||
|
||||
case 4: // Worgs & Wolves
|
||||
SetLocalString(oArea, sEncNum, "v2, night, 12.5, group, worgs");
|
||||
SetLocalString(oArea, "group_worgs_01", "creature, NW_WORG, 1-3, wp: worgs, 1.0, 1, 1");
|
||||
SetLocalString(oArea, "group_worgs_02", "creature, NW_WOLF, 1-12, last, 5.0, 1, 1");
|
||||
break;
|
||||
|
||||
case 5: // Shadows
|
||||
SetLocalString(oArea, sEncNum, "v2, night, 7, creature, RA_SHADOW001, 2-12, random, 1.0, 1, 1");
|
||||
break;
|
||||
|
||||
case 6: // Orge & Bugbears
|
||||
SetLocalString(oArea, sEncNum, "v2, day, 7, group, ogrebugs");
|
||||
SetLocalString(oArea, "group_ogrebugs_01", "creature, NW_OGRE01, 1, wp: ogrebugs, 1.0, 1, 1");
|
||||
SetLocalString(oArea, "group_ogrebugs_02", "creature, NW_BUGBEARA, 1-2, last, 5.0, 1, 1");
|
||||
SetLocalString(oArea, "group_ogrebugs_03", "creature, NW_BUGBEARB, 1-2, last, 5.0, 1, 1");
|
||||
break;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
//void main(){}
|
70
_module/nss/sparky_enter.nss
Normal file
70
_module/nss/sparky_enter.nss
Normal file
@@ -0,0 +1,70 @@
|
||||
/* Generic area onEnter script for streamlined addition of Sparky Spawner variables
|
||||
Created By: The Amethyst Dragon (www.amethyst-dragon.com/nwn)
|
||||
|
||||
Can be used for the onEnter script for all areas of a module. If you already
|
||||
have your own area enter script, you can add just the includes and the
|
||||
"Sparky Spawner Section" of code.
|
||||
|
||||
This causes the area to check to see if Sparky variables are set on the area.
|
||||
|
||||
If not, it searches for the Encounter Variables placeable object in the area
|
||||
to find out which variables to add to the area, then runs the Sparky spawning
|
||||
code.
|
||||
|
||||
If no such variables or placeable are present in the area, it skips any further
|
||||
Sparky code from running.
|
||||
*/
|
||||
|
||||
#include "sparky_inc"
|
||||
#include "sparky_enc"
|
||||
#include "X0_I0_PARTYWIDE"
|
||||
|
||||
void main()
|
||||
{
|
||||
object oPC = GetEnteringObject();
|
||||
object oArea = OBJECT_SELF;
|
||||
|
||||
if (GetIsPC(oPC) == TRUE) // Nothing happens if it wasn't a PC entering the area.
|
||||
{
|
||||
//////////////////////////////////////////////// Sparky Spawner Section
|
||||
if (GetLocalInt(oArea, "sparkyloaded") != 1)
|
||||
{
|
||||
// Find encounters-holding placeable
|
||||
object oEncVars = GetFirstObjectInArea(oArea);
|
||||
while (oEncVars != OBJECT_INVALID)
|
||||
{
|
||||
if (GetTag(oEncVars) == "sparky_variables") { break; }
|
||||
oEncVars = GetNextObjectInArea(oArea);
|
||||
}
|
||||
if (oEncVars != OBJECT_INVALID)
|
||||
{
|
||||
LoadEncounterVariables(oArea, GetLocalInt(oEncVars, "enc01"));
|
||||
LoadEncounterVariables(oArea, GetLocalInt(oEncVars, "enc02"));
|
||||
LoadEncounterVariables(oArea, GetLocalInt(oEncVars, "enc03"));
|
||||
LoadEncounterVariables(oArea, GetLocalInt(oEncVars, "enc04"));
|
||||
LoadEncounterVariables(oArea, GetLocalInt(oEncVars, "enc05"));
|
||||
LoadEncounterVariables(oArea, GetLocalInt(oEncVars, "enc06"));
|
||||
LoadEncounterVariables(oArea, GetLocalInt(oEncVars, "enc07"));
|
||||
LoadEncounterVariables(oArea, GetLocalInt(oEncVars, "enc08"));
|
||||
LoadEncounterVariables(oArea, GetLocalInt(oEncVars, "enc09"));
|
||||
LoadEncounterVariables(oArea, GetLocalInt(oEncVars, "enc10"));
|
||||
DestroyObject(oEncVars, 1.0);
|
||||
}
|
||||
SetLocalInt(oArea, "sparkyloaded", 1);
|
||||
}
|
||||
int iDisabled = GetLocalInt(oArea, "iSparkyDisabled");
|
||||
int iAlreadySpawned = GetLocalInt(oArea, "iSparkySpawned");
|
||||
|
||||
if (GetIsDM(oPC))
|
||||
{
|
||||
SendMessageToPC(oPC, "Sparky spawns are " + (iDisabled ? "OFF" : "ON"));
|
||||
return;
|
||||
}
|
||||
if (iAlreadySpawned || iDisabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
SpawnEncounters(oArea);
|
||||
//////////////////////////////////////////////// End Sparky Section
|
||||
}
|
||||
}
|
37
_module/nss/sparky_exit.nss
Normal file
37
_module/nss/sparky_exit.nss
Normal file
@@ -0,0 +1,37 @@
|
||||
/* Generic area onExit script for use with the Sparky Spawner scripting
|
||||
Created By: The Amethyst Dragon (www.amethyst-dragon.com/nwn)
|
||||
|
||||
Can be used for the onExit script for all areas of a module. If you already
|
||||
have your own area enter script, you can add just the include and the
|
||||
"Sparky Spawner" Sections of code (one function, one bit of code to execute).
|
||||
|
||||
This searches the area for remaining PCs, and if it doesn't find any, it
|
||||
despawns all the things in the area created by the Sparky spawner.
|
||||
*/
|
||||
|
||||
#include "sparky_inc"
|
||||
|
||||
//////////////////////////////////////////////// Sparky Spawner Section 1 of 2
|
||||
int CheckForPCs()
|
||||
{
|
||||
object oPC = GetFirstPC();
|
||||
while (oPC != OBJECT_INVALID)
|
||||
{
|
||||
if (GetArea(oPC) == OBJECT_SELF) { return TRUE; }
|
||||
oPC = GetNextPC();
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
//////////////////////////////////////////////// End Sparky Section 1 of 2
|
||||
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
object oArea = OBJECT_SELF;
|
||||
|
||||
//////////////////////////////////////////////// Sparky Spawner Section 2 of 2
|
||||
if (CheckForPCs() == FALSE) { Despawn(oArea); }
|
||||
//////////////////////////////////////////////// End Sparky Section 2 of 2
|
||||
|
||||
}
|
1394
_module/nss/sparky_inc.nss
Normal file
1394
_module/nss/sparky_inc.nss
Normal file
File diff suppressed because it is too large
Load Diff
@@ -31,6 +31,16 @@ void DespawnChildrenByTag(object oSpawn, string sSpawnTag);
|
||||
//
|
||||
//
|
||||
|
||||
// tinygiant -- set this to FALSE to turn off debug statement
|
||||
const int IS_DEBUGGING = TRUE;
|
||||
|
||||
// tinygiant -- temporary function to send debug messages
|
||||
void Debug(string sMessage)
|
||||
{
|
||||
if (IS_DEBUGGING)
|
||||
SendMessageToPC(GetFirstPC(), sMessage);
|
||||
}
|
||||
|
||||
string GetTemplateByCR(int nCR, string sGroupType)
|
||||
{
|
||||
string sRetTemplate;
|
||||
@@ -38,34 +48,34 @@ string GetTemplateByCR(int nCR, string sGroupType)
|
||||
if (sGroupType == "outdoor")
|
||||
{
|
||||
switch (nCR)
|
||||
{
|
||||
{
|
||||
case 1:
|
||||
switch(d6(1))
|
||||
{
|
||||
case 1: sRetTemplate = "NW_SKELETON"; break;
|
||||
case 2: sRetTemplate = "NW_ZOMBIE01"; break;
|
||||
case 3: sRetTemplate = "NW_NIXIE"; break;
|
||||
case 4: sRetTemplate = "NW_ORCA"; break;
|
||||
case 5: sRetTemplate = "NW_ORCB"; break;
|
||||
case 6: sRetTemplate = "NW_BTLFIRE"; break;
|
||||
case 1: sRetTemplate = "NW_SKELETON"; break;
|
||||
case 2: sRetTemplate = "NW_ZOMBIE01"; break;
|
||||
case 3: sRetTemplate = "NW_NIXIE"; break;
|
||||
case 4: sRetTemplate = "NW_ORCA"; break;
|
||||
case 5: sRetTemplate = "NW_ORCB"; break;
|
||||
case 6: sRetTemplate = "NW_BTLFIRE"; break;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
switch(d4(1))
|
||||
{
|
||||
case 1: sRetTemplate = "NW_KOBOLD004"; break;
|
||||
case 2: sRetTemplate = "NW_KOBOLD005"; break;
|
||||
case 3: sRetTemplate = "NW_KOBOLD003"; break;
|
||||
case 4: sRetTemplate = "NW_PIXIE"; break;
|
||||
case 1: sRetTemplate = "NW_KOBOLD004"; break;
|
||||
case 2: sRetTemplate = "NW_KOBOLD005"; break;
|
||||
case 3: sRetTemplate = "NW_KOBOLD003"; break;
|
||||
case 4: sRetTemplate = "NW_PIXIE"; break;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
switch(d4(1))
|
||||
{
|
||||
case 1: sRetTemplate = "NW_BTLBOMB"; break;
|
||||
case 2: sRetTemplate = "NW_BTLFIRE002"; break;
|
||||
case 3: sRetTemplate = "NW_BTLSTINK"; break;
|
||||
case 4: sRetTemplate = "NW_NYMPH"; break;
|
||||
case 1: sRetTemplate = "NW_BTLBOMB"; break;
|
||||
case 2: sRetTemplate = "NW_BTLFIRE002"; break;
|
||||
case 3: sRetTemplate = "NW_BTLSTINK"; break;
|
||||
case 4: sRetTemplate = "NW_NYMPH"; break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -77,18 +87,18 @@ string GetTemplateByCR(int nCR, string sGroupType)
|
||||
else if (sGroupType == "crypt")
|
||||
{
|
||||
switch (nCR)
|
||||
{
|
||||
{
|
||||
case 1:
|
||||
switch(d4(1))
|
||||
{
|
||||
case 1:
|
||||
case 2: sRetTemplate = "NW_SKELETON"; break;
|
||||
case 3: sRetTemplate = "NW_ZOMBIE01"; break;
|
||||
case 4: sRetTemplate = "NW_ZOMBIE02"; break;
|
||||
case 1:
|
||||
case 2: sRetTemplate = "NW_SKELETON"; break;
|
||||
case 3: sRetTemplate = "NW_ZOMBIE01"; break;
|
||||
case 4: sRetTemplate = "NW_ZOMBIE02"; break;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
sRetTemplate = "NW_GHOUL";
|
||||
sRetTemplate = "NW_GHOUL";
|
||||
break;
|
||||
case 3:
|
||||
sRetTemplate = "NW_SHADOW";
|
||||
@@ -108,7 +118,7 @@ string GetTemplateByCR(int nCR, string sGroupType)
|
||||
}
|
||||
|
||||
|
||||
// Convert a given EL equivalent and its encounter level,
|
||||
// Convert a given EL equivalent and its encounter level,
|
||||
// return the corresponding CR
|
||||
float ConvertELEquivToCR(float fEquiv, float fEncounterLevel)
|
||||
{
|
||||
@@ -137,8 +147,8 @@ float ConvertCRToELEquiv(float fCR, float fEncounterLevel)
|
||||
|
||||
float fEquiv, fExponent, fDenom;
|
||||
|
||||
fExponent = fEncounterLevel - fCR;
|
||||
fExponent *= 0.5;
|
||||
fExponent = fEncounterLevel - fCR;
|
||||
fExponent *= 0.5;
|
||||
fDenom = pow(2.0, fExponent);
|
||||
fEquiv = 1.0 / fDenom;
|
||||
|
||||
@@ -147,6 +157,11 @@ float ConvertCRToELEquiv(float fCR, float fEncounterLevel)
|
||||
|
||||
string SpawnGroup(object oSpawn, string sTemplate)
|
||||
{
|
||||
Debug("NESS: Running function SpawnGroup");
|
||||
Debug(" oSpawn -> " + GetName(oSpawn));
|
||||
Debug(" sTemplate -> " + sTemplate);
|
||||
Debug("");
|
||||
|
||||
// Initialize
|
||||
string sRetTemplate;
|
||||
|
||||
@@ -165,7 +180,7 @@ string SpawnGroup(object oSpawn, string sTemplate)
|
||||
{
|
||||
float fEncounterLevel;
|
||||
int nScaledInProgress = GetLocalInt(oSpawn, "ScaledInProgress");
|
||||
string sGroupType = GetStringRight(sTemplate,
|
||||
string sGroupType = GetStringRight(sTemplate,
|
||||
GetStringLength(sTemplate) - 7);
|
||||
|
||||
// First Time in for this encounter?
|
||||
@@ -177,7 +192,7 @@ string SpawnGroup(object oSpawn, string sTemplate)
|
||||
int nTotalPCLevel = 0;
|
||||
|
||||
object oArea = GetArea(OBJECT_SELF);
|
||||
|
||||
|
||||
object oPC = GetFirstObjectInArea(oArea);
|
||||
while (oPC != OBJECT_INVALID)
|
||||
{
|
||||
@@ -203,7 +218,7 @@ string SpawnGroup(object oSpawn, string sTemplate)
|
||||
// We're done when the CRs chosen add up to the
|
||||
// desired encounter level
|
||||
SetLocalInt(oSpawn, "ScaledCallCount", 0);
|
||||
SetLocalInt(oSpawn, "ScaledInProgress", TRUE);
|
||||
SetLocalInt(oSpawn, "ScaledInProgress", TRUE);
|
||||
}
|
||||
|
||||
|
||||
@@ -232,7 +247,7 @@ string SpawnGroup(object oSpawn, string sTemplate)
|
||||
sRetTemplate = GetTemplateByCR(nCR, sGroupType);
|
||||
|
||||
|
||||
// Convert CR to Encounter Level equivalent so it can be correctly
|
||||
// Convert CR to Encounter Level equivalent so it can be correctly
|
||||
// subtracted. This does the real scaling work
|
||||
float fELEquiv = ConvertCRToELEquiv(IntToFloat(nCR), fEncounterLevel);
|
||||
float fElRemaining = 1.0 - fELEquiv;
|
||||
@@ -245,10 +260,10 @@ string SpawnGroup(object oSpawn, string sTemplate)
|
||||
SetLocalInt(oSpawn, "ScaledCallCount", nScaledCallCount);
|
||||
|
||||
nSpawnNumber = GetLocalInt(oSpawn, "f_SpawnNumber");
|
||||
|
||||
if (nScaledCallCount >= nSpawnNumber)
|
||||
|
||||
if (nScaledCallCount >= nSpawnNumber)
|
||||
{
|
||||
// reset...
|
||||
// reset...
|
||||
SetLocalInt(oSpawn, "ScaledInProgress", FALSE);
|
||||
}
|
||||
}
|
||||
@@ -295,31 +310,87 @@ string SpawnGroup(object oSpawn, string sTemplate)
|
||||
sRetTemplate = "NW_GOBLINB";
|
||||
}
|
||||
}
|
||||
//
|
||||
|
||||
// Brigands & Leader
|
||||
if (sTemplate == "brigands01")
|
||||
{
|
||||
int nIsBossSpawned = GetLocalInt(oSpawn, "IsBossSpawned");
|
||||
|
||||
Debug("NESS: nIsBossSpawned :: oSpawn -> " + GetName(oSpawn));
|
||||
Debug("NESS: nIsBossSpawned :: Value -> " + IntToString(nIsBossSpawned));
|
||||
|
||||
if (nIsBossSpawned == TRUE)
|
||||
{
|
||||
// Find the Boss
|
||||
object oBoss = GetChildByTag(oSpawn, "RA_BRIGAND002");
|
||||
|
||||
Debug("NESS: oBoss -> " + (GetIsObjectValid(oBoss) ? GetName(oBoss) : "OBJECT_INVALID"));
|
||||
|
||||
// Check if Boss is Alive
|
||||
if (oBoss != OBJECT_INVALID && GetIsDead(oBoss) == FALSE)
|
||||
{
|
||||
Debug("NESS: oBoss is valid and alive, assigning template 'RA_BRIGAND001'");
|
||||
|
||||
// He's alive, spawn a Peon to keep him Company
|
||||
sRetTemplate = "RA_BRIGAND001";
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug("NESS: oBoss is either invalid or dead, so let's respawn him.");
|
||||
sRetTemplate = "RA_BRIGAND002";
|
||||
SetLocalInt(oSpawn, "IsBossSpawned", TRUE);
|
||||
// He's dead, Deactivate Camp!
|
||||
//SetLocalInt(oSpawn, "SpawnDeactivated", TRUE);
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug("NESS: Boss does not exist, assiging template 'RA_BRIGAND002'");
|
||||
|
||||
// No Boss, so Let's Spawn Him
|
||||
sRetTemplate = "RA_BRIGAND002";
|
||||
SetLocalInt(oSpawn, "IsBossSpawned", TRUE);
|
||||
}
|
||||
}
|
||||
//
|
||||
|
||||
// Goblins and Boss
|
||||
if (sTemplate == "gobsnboss")
|
||||
{
|
||||
int nIsBossSpawned = GetLocalInt(oSpawn, "IsBossSpawned");
|
||||
|
||||
Debug("NESS: nIsBossSpawned :: oSpawn -> " + GetName(oSpawn));
|
||||
Debug("NESS: nIsBossSPawned :: Value -> " + IntToString(nIsBossSpawned));
|
||||
|
||||
if (nIsBossSpawned == TRUE)
|
||||
{
|
||||
// Find the Boss
|
||||
object oBoss = GetChildByTag(oSpawn, "NW_GOBCHIEFA");
|
||||
|
||||
Debug("NESS: oBoss -> " + (GetIsObjectValid(oBoss) ? GetName(oBoss) : "OBJECT_INVALID"));
|
||||
|
||||
// Check if Boss is Alive
|
||||
if (oBoss != OBJECT_INVALID && GetIsDead(oBoss) == FALSE)
|
||||
{
|
||||
Debug("NESS: oBoss is valid and alive, assigning templatle 'NW_GOBLINA'");
|
||||
|
||||
// He's alive, spawn a Peon to keep him Company
|
||||
sRetTemplate = "NW_GOBLINA";
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug("NESS: oBoss is either invalid or dead, deactivating camp");
|
||||
|
||||
// He's dead, Deactivate Camp!
|
||||
SetLocalInt(oSpawn, "SpawnDeactivated", TRUE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug("NESS: Boss does not exist, assiging template 'NW_GOBCHIEFA'");
|
||||
|
||||
// No Boss, so Let's Spawn Him
|
||||
sRetTemplate = "NW_GOBCHIEFA";
|
||||
SetLocalInt(oSpawn, "IsBossSpawned", TRUE);
|
||||
@@ -539,3 +610,4 @@ string SpawnGroup(object oSpawn, string sTemplate)
|
||||
//
|
||||
return sRetTemplate;
|
||||
}
|
||||
//void main (){}
|
||||
|
@@ -1674,6 +1674,8 @@ void DoSpawn(object oSpawn, int nTimeNow)
|
||||
nObjectType = OBJECT_TYPE_STORE;
|
||||
}
|
||||
|
||||
SendMessageToPC(GetFirstPC(), "NESS: Checking for group spawn");
|
||||
|
||||
// Check Spawn Group
|
||||
if (nSpawnGroup == TRUE)
|
||||
{
|
||||
@@ -1685,6 +1687,9 @@ void DoSpawn(object oSpawn, int nTimeNow)
|
||||
sTemplate = sSpawnTag;
|
||||
}
|
||||
|
||||
SendMessageToPC(GetFirstPC(), "NESS: nSpawnGroup -> " + (nSpawnGroup ? "TRUE" : "FALSE"));
|
||||
SendMessageToPC(GetFirstPC(), "NESS: sTemplate -> " + sTemplate);
|
||||
|
||||
// Set up alternate Entrance/Exit
|
||||
if (!nSpawnCamp)
|
||||
{
|
||||
|
91
_module/nss/spawn_sit.nss
Normal file
91
_module/nss/spawn_sit.nss
Normal file
@@ -0,0 +1,91 @@
|
||||
//::///////////////////////////////////////////////
|
||||
//:: Name x2_def_spawn
|
||||
//:: Copyright (c) 2001 Bioware Corp.
|
||||
//:://////////////////////////////////////////////
|
||||
/*
|
||||
Default On Spawn script
|
||||
|
||||
|
||||
2003-07-28: Georg Zoeller:
|
||||
|
||||
If you set a ninteger on the creature named
|
||||
"X2_USERDEFINED_ONSPAWN_EVENTS"
|
||||
The creature will fire a pre and a post-spawn
|
||||
event on itself, depending on the value of that
|
||||
variable
|
||||
1 - Fire Userdefined Event 1510 (pre spawn)
|
||||
2 - Fire Userdefined Event 1511 (post spawn)
|
||||
3 - Fire both events
|
||||
|
||||
2007-12-31: Deva Winblood
|
||||
Modified to look for X3_HORSE_OWNER_TAG and if
|
||||
it is defined look for an NPC with that tag
|
||||
nearby or in the module (checks near first).
|
||||
It will make that NPC this horse's master.
|
||||
|
||||
*/
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Created By: Keith Warner, Georg Zoeller
|
||||
//:: Created On: June 11/03
|
||||
//:://////////////////////////////////////////////
|
||||
|
||||
const int EVENT_USER_DEFINED_PRESPAWN = 1510;
|
||||
const int EVENT_USER_DEFINED_POSTSPAWN = 1511;
|
||||
|
||||
|
||||
#include "x2_inc_switches"
|
||||
void main()
|
||||
{
|
||||
string sTag;
|
||||
object oNPC;
|
||||
// User defined OnSpawn event requested?
|
||||
int nSpecEvent = GetLocalInt(OBJECT_SELF,"X2_USERDEFINED_ONSPAWN_EVENTS");
|
||||
|
||||
|
||||
// Pre Spawn Event requested
|
||||
if (nSpecEvent == 1 || nSpecEvent == 3 )
|
||||
{
|
||||
SignalEvent(OBJECT_SELF,EventUserDefined(EVENT_USER_DEFINED_PRESPAWN ));
|
||||
}
|
||||
|
||||
sTag=GetLocalString(OBJECT_SELF,"X3_HORSE_OWNER_TAG");
|
||||
if (GetStringLength(sTag)>0)
|
||||
{ // look for master
|
||||
oNPC=GetNearestObjectByTag(sTag);
|
||||
if (GetIsObjectValid(oNPC)&&GetObjectType(oNPC)==OBJECT_TYPE_CREATURE)
|
||||
{ // master found
|
||||
AddHenchman(oNPC);
|
||||
} // master found
|
||||
else
|
||||
{ // look in module
|
||||
oNPC=GetObjectByTag(sTag);
|
||||
if (GetIsObjectValid(oNPC)&&GetObjectType(oNPC)==OBJECT_TYPE_CREATURE)
|
||||
{ // master found
|
||||
AddHenchman(oNPC);
|
||||
} // master found
|
||||
else
|
||||
{ // master does not exist - remove X3_HORSE_OWNER_TAG
|
||||
DeleteLocalString(OBJECT_SELF,"X3_HORSE_OWNER_TAG");
|
||||
} // master does not exist - remove X3_HORSE_OWNER_TAG
|
||||
} // look in module
|
||||
} // look for master
|
||||
|
||||
/* Fix for the new golems to reduce their number of attacks */
|
||||
|
||||
int nNumber = GetLocalInt(OBJECT_SELF,CREATURE_VAR_NUMBER_OF_ATTACKS);
|
||||
if (nNumber >0 )
|
||||
{
|
||||
SetBaseAttackBonus(nNumber);
|
||||
}
|
||||
|
||||
// Execute default OnSpawn script.
|
||||
ExecuteScript("nw_c2_default9", OBJECT_SELF);
|
||||
|
||||
|
||||
//Post Spawn event requeste
|
||||
if (nSpecEvent == 2 || nSpecEvent == 3)
|
||||
{
|
||||
SignalEvent(OBJECT_SELF,EventUserDefined(EVENT_USER_DEFINED_POSTSPAWN));
|
||||
}
|
||||
ActionPlayAnimation(ANIMATION_LOOPING_SIT_CROSS,1.0,10000.0f);
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// NESS V8.1.3
|
||||
// NESS V8.1.2
|
||||
//
|
||||
// Spawn sample onEnter, version 2
|
||||
//
|
||||
@@ -31,4 +31,4 @@ void main()
|
||||
// Outdoors or underground - do a 3 second delay on the first HB
|
||||
Spawn_OnAreaEnter( "spawn_sample_hb", 10.0, 3.0 );
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// NESS V8.1.3
|
||||
// NESS V8.1
|
||||
//
|
||||
// Spawn sample onEnter
|
||||
//
|
||||
// If you want to use pseudo-heartbeats and do not already have an area onEnter
|
||||
// script, you can use this one. Otherwise, just add Spawn_OnAreaEnter() to
|
||||
// your existing onEnter handler. Note that you use this (and
|
||||
// your existing onEnter handler. Note that you use this (and
|
||||
// SpawnOnAreaExit()) INSTEAD OF Spawn() / spawn_sample_hb.
|
||||
//
|
||||
//
|
||||
|
||||
#include "spawn_functions"
|
||||
|
||||
@@ -15,9 +15,9 @@ void main()
|
||||
{
|
||||
// Spawn_OnAreaEnter() can take three arguments - the name of the heartbeat
|
||||
// script to execute, the heartbeat duration, and a delay for the first
|
||||
// heartbeat. They default to spawn_sample_hb, 6.0, and 0.0 respectively; as
|
||||
// heartbeat. They default to spawn_sample_hb, 6.0, and 0.0 respectively; as
|
||||
// if it were called like:
|
||||
// Spawn_OnAreaEnter( "spawn_sample_hb", 6.0, 0.0 );
|
||||
|
||||
Spawn_OnAreaEnter();
|
||||
}
|
||||
}
|
72
_module/nss/tgdc_explore_inc.nss
Normal file
72
_module/nss/tgdc_explore_inc.nss
Normal file
@@ -0,0 +1,72 @@
|
||||
|
||||
//Checks to see if the player has been in the current area and
|
||||
//if they have not, sends description and awards XP.
|
||||
//oPC = Player nReveal: 1 = Reveals whole map - 0 = Does not - 2 Hides Map
|
||||
//Info Type can be classed as the following:
|
||||
void PlayerExplore(object oPC, int nReveal);
|
||||
|
||||
void PlayerExplore(object oPC, int nReveal)
|
||||
{
|
||||
if (!GetIsPC(oPC)) return;
|
||||
if (nReveal == 1)ExploreAreaForPlayer(GetArea(oPC), oPC, TRUE);
|
||||
if (nReveal == 2)ExploreAreaForPlayer(GetArea(oPC), oPC, FALSE);
|
||||
|
||||
//GET AREA DETAILS
|
||||
object oArea = GetArea(oPC);
|
||||
string sArea = GetTag(oArea);
|
||||
//DATABASE FUNCTIONS GO HERE
|
||||
int nHasExplored = GetCampaignInt("Exploring Athas", sArea, oPC);
|
||||
if (nHasExplored == 1) return;
|
||||
//AREAS START FROM HERE
|
||||
//ADD ONE "if (sArea =="") FOR EACH AREA YOU WISH TO DESCRIBE
|
||||
|
||||
if (sArea == "ALT_ALTARUK")//THE VARIABLE USED IS THE TAG OF THE AREA
|
||||
{
|
||||
//EDIT THE XP GIVEN AND JOURNAL ENTRY ID NUMBER TO SUIT
|
||||
AddJournalQuestEntry("Exploring Athas", 1, oPC, FALSE, FALSE);//ONLY CHANGE THE ID NUMBER
|
||||
GiveXPToCreature(oPC, 20);//DEFAULT IS 10 XP
|
||||
SetCampaignInt("Exploring Athas", sArea, 1, oPC);//DO NOT CHANGE THIS NUMBER
|
||||
return;
|
||||
}
|
||||
|
||||
if (sArea == "KLED_VILLAGE")//THE VARIABLE USED IS THE TAG OF THE AREA
|
||||
{
|
||||
//EDIT THE XP GIVEN AND JOURNAL ENTRY ID NUMBER TO SUIT
|
||||
AddJournalQuestEntry("Exploring Athas", 2, oPC, FALSE, FALSE);//ONLY CHANGE THE ID NUMBER
|
||||
GiveXPToCreature(oPC, 20);//DEFAULT IS 10 XP
|
||||
SetCampaignInt("Exploring Athas", sArea, 1, oPC);//DO NOT CHANGE THIS NUMBER
|
||||
return;
|
||||
}
|
||||
|
||||
if (sArea == "TYR_CARAVANWAY")//THE VARIABLE USED IS THE TAG OF THE AREA
|
||||
{
|
||||
//EDIT THE XP GIVEN AND JOURNAL ENTRY ID NUMBER TO SUIT
|
||||
AddJournalQuestEntry("Exploring Athas", 3, oPC, FALSE, FALSE);//ONLY CHANGE THE ID NUMBER
|
||||
GiveXPToCreature(oPC, 10);//DEFAULT IS 10 XP
|
||||
SetCampaignInt("Exploring Athas", sArea, 1, oPC);//DO NOT CHANGE THIS NUMBER
|
||||
return;
|
||||
}
|
||||
|
||||
if (sArea == "URIK_OBSIDGATE")//THE VARIABLE USED IS THE TAG OF THE AREA
|
||||
{
|
||||
//EDIT THE XP GIVEN AND JOURNAL ENTRY ID NUMBER TO SUIT
|
||||
AddJournalQuestEntry("Exploring Athas", 4, oPC, FALSE, FALSE);//ONLY CHANGE THE ID NUMBER
|
||||
GiveXPToCreature(oPC, 30);//DEFAULT IS 10 XP
|
||||
SetCampaignInt("Exploring Athas", sArea, 1, oPC);//DO NOT CHANGE THIS NUMBER
|
||||
return;
|
||||
}
|
||||
|
||||
if (sArea == "SilverSpringsOasis")//THE VARIABLE USED IS THE TAG OF THE AREA
|
||||
{
|
||||
//EDIT THE XP GIVEN AND JOURNAL ENTRY ID NUMBER TO SUIT
|
||||
AddJournalQuestEntry("Exploring Athas", 5, oPC, FALSE, FALSE);//ONLY CHANGE THE ID NUMBER
|
||||
GiveXPToCreature(oPC, 40);//DEFAULT IS 10 XP
|
||||
SetCampaignInt("Exploring Athas", sArea, 1, oPC);//DO NOT CHANGE THIS NUMBER
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//void main(){}
|
||||
|
19
_module/nss/x2_def_heartbeat.nss
Normal file
19
_module/nss/x2_def_heartbeat.nss
Normal file
@@ -0,0 +1,19 @@
|
||||
//::///////////////////////////////////////////////
|
||||
//:: Name x2_def_heartbeat
|
||||
//:: Copyright (c) 2001 Bioware Corp.
|
||||
//:://////////////////////////////////////////////
|
||||
/*
|
||||
Default Heartbeat script
|
||||
*/
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Created By: Keith Warner
|
||||
//:: Created On: June 11/03
|
||||
//:://////////////////////////////////////////////
|
||||
|
||||
void main()
|
||||
{
|
||||
if ((!GetIsInCombat(OBJECT_SELF) && (GetItemInSlot(INVENTORY_SLOT_CHEST) == OBJECT_INVALID)))
|
||||
DelayCommand(0.5f, ActionEquipMostEffectiveArmor());
|
||||
|
||||
ExecuteScript("nw_c2_default1", OBJECT_SELF);
|
||||
}
|
@@ -2,7 +2,7 @@
|
||||
//:: Name x2_def_ondeath
|
||||
//:: Copyright (c) 2001 Bioware Corp.
|
||||
//:://////////////////////////////////////////////
|
||||
/*
|
||||
/* ra_brigand002
|
||||
Default OnDeath script
|
||||
*/
|
||||
//:://////////////////////////////////////////////
|
||||
@@ -14,8 +14,12 @@ void main()
|
||||
{
|
||||
object oNPC = OBJECT_SELF;
|
||||
|
||||
// Makes sure armor's droppable flag is set to 0
|
||||
SetDroppableFlag(GetItemInSlot(INVENTORY_SLOT_CHEST, OBJECT_SELF), 0);
|
||||
|
||||
if ((GetResRef(oNPC) == "ra_bandit001") ||
|
||||
(GetResRef(oNPC) == "ra_brigand001"))
|
||||
(GetResRef(oNPC) == "ra_brigand001") ||
|
||||
(GetResRef(oNPC) == "ra_brigand002"))
|
||||
{
|
||||
object oArmor = GetItemInSlot(INVENTORY_SLOT_CHEST, oNPC);
|
||||
object oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oNPC);
|
||||
|
Reference in New Issue
Block a user