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