NWNDS/nwnds_module/sc_grignardeath.nss
Jaysyn904 de24f81734 Added NWN Dark Sun module contents
Added NWN Dark Sun module contents.
2021-07-12 21:24:46 -04:00

225 lines
8.6 KiB
Plaintext

/************************ [On Death] *******************************************
Filename: j_ai_ondeath or nw_c2_default7
************************* [On Death] *******************************************
Speeded up no end, when compiling, with seperate Include.
Cleans up all un-droppable items, all ints and all local things when destroyed.
Check down near the bottom for a good place to add XP or corpse lines ;-)
************************* [History] ********************************************
1.3 - Added in Turn of corpses toggle
- Added in appropriate space for XP awards, marked with ideas (effect death)
************************* [Workings] *******************************************
You can edit this for experience, there is a seperate section for it.
It will use DeathCheck to execute a cleanup-and-destroy script, that removes
any coprse, named "j_ai_destroyself".
************************* [Arguments] ******************************************
Arguments: GetLastKiller.
************************* [On Death] ******************************************/
// We only require the constants/debug file. We have 1 function, not worth another include.
#include "j_inc_constants"
// We need a wrapper. If the amount of deaths, got in this, is not equal to iDeaths,
// we don't execute the script, else we do. :-P
void DeathCheck(int iDeaths);
void ClearSlot(int iSlotID);
void PartyGold(object oPC);
void main()
{
// initialise local variables
int nKillFlag = GetLocalInt(GetLastKiller(), "KILL_TASK_FLAG");
object oPC = GetLastKiller();
while (GetIsObjectValid(GetMaster(oPC)))
{
oPC=GetMaster(oPC);
}
string sTagSelf = GetTag(OBJECT_SELF);
string sTagTarget = GetLocalString(oPC, "KILL_TASK_TARGET");
PartyGold(oPC);
SpeakString("Curse you! They left me to die! They should starve!", TALKVOLUME_TALK);
CreateItemOnObject("storeroomkey", oPC);
// check for correct kill task target and complete
if(sTagSelf == sTagTarget && nKillFlag == 1) {
SetLocalInt(oPC, "KILL_TASK_FLAG", 2);
AddJournalQuestEntry("kt_journal_01", 99, oPC);
}
}
void ClearSlot(int iSlotID)
{
object oItem = GetItemInSlot(iSlotID);
if(GetIsObjectValid(oItem))
{
if(!GetDroppableFlag(oItem))
DestroyObject(oItem);
}
}
void PartyGold(object oPC)
{
int nHD = GetHitDice(OBJECT_SELF);
int nGold = ((nHD - 3) * 4) + d20();
// This code shows how you can cycle through all the party members of the first PC
object oPartyMember = GetFirstFactionMember(oPC, TRUE);
int nMembers = 0;
while (GetIsObjectValid(oPartyMember) == TRUE)
{
// count party members
nMembers++;
oPartyMember = GetNextFactionMember(oPartyMember, TRUE);
}
if (nMembers < 1)
nMembers = 1;
int nShare = (nGold / nMembers);
oPartyMember = GetFirstFactionMember(oPC, TRUE);
while (GetIsObjectValid(oPartyMember) == TRUE)
{
GiveGoldToCreature(oPartyMember, nShare);
oPartyMember = GetNextFactionMember(oPartyMember, TRUE);
}
// If we are set to, don't fire this script at all
if(GetAIInteger(I_AM_TOTALLY_DEAD)) return;
// Pre-death-event
if(FireUserEvent(AI_FLAG_UDE_DEATH_PRE_EVENT, EVENT_DEATH_PRE_EVENT))
// We may exit if it fires
if(ExitFromUDE(EVENT_DEATH_PRE_EVENT)) return;
// Note: No AI on/off check here.
// Who killed us? (alignment changing, debug, XP).
object oKiller = GetLastKiller();
// Stops if we just applied EffectDeath to ourselves.
if(GetLocalTimer(AI_TIMER_DEATH_EFFECT_DEATH)) return;
// Special: To stop giving out multiple amounts of XP, we use EffectDeath
// to change the killer, so the XP systems will NOT award MORE XP.
// - Even the default one suffers from this!
if(GetAIInteger(WE_HAVE_DIED_ONCE))
{
if(!GetLocalTimer(AI_TIMER_DEATH_EFFECT_DEATH))
{
// Don't apply effect death to self more then once per 2 seconds.
SetLocalTimer(AI_TIMER_DEATH_EFFECT_DEATH, f2);
// This should make the last killer us.
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectResurrection(), OBJECT_SELF);
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(GetMaxHitPoints()), OBJECT_SELF);
}
}
else if(oKiller != OBJECT_SELF)
{
// Set have died once, stops giving out mulitple amounts of XP.
SetAIInteger(WE_HAVE_DIED_ONCE, TRUE);
/************************ [Experience] *****************************************
THIS is the place for it, below this comment. To reward XP, you might want
to first apply EffectDeath to ourselves (uncomment the example lines) which
will remove the "You recieved 0 Experience" if you have normal XP at 0, as
the On Death event is before the reward, and therefore now our last killer
will be outselves. It will not cause any errors, oKiller is already set.
Anything else, I leave to you. GetFirstFactionMember (and next), GiveXPToCreature,
GetXP, SetXP, GetChallengeRating all are really useful.
Bug note: GetFirstFactionMember/Next with the PC parameter means either ONLY PC
************************* [Experience] ****************************************/
// Do XP things (Use object "oKiller").
/************************ [Experience] ****************************************/
}
// Note: Here we do a simple way of checking how many times we have died.
// Nothing special. Debugging most useful aspect.
int iDeathCounterNew = GetAIInteger(AMOUNT_OF_DEATHS);
iDeathCounterNew++;
SetAIInteger(AMOUNT_OF_DEATHS, iDeathCounterNew);
// Here is the last time (in game seconds) we died. It is used in the executed script
// to make sure we don't prematurly remove areselves.
// We may want some sort of visual effect - like implosion or something, to fire.
int iDeathEffect = GetAIConstant(AI_DEATH_VISUAL_EFFECT);
// Valid constants from 0 and up. Apply to our location (not to us, who will go!)
if(iDeathEffect >= i0)
{
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, EffectVisualEffect(iDeathEffect), GetLocation(OBJECT_SELF));
}
// Default Commoner alignment changing. (If the commoner is not evil!)
if(GetLevelByClass(CLASS_TYPE_COMMONER) > i0 &&
GetAlignmentGoodEvil(OBJECT_SELF) != ALIGNMENT_EVIL &&
!GetSpawnInCondition(AI_FLAG_OTHER_NO_COMMONER_ALIGNMENT_CHANGE, AI_OTHER_MASTER))
{
if(GetIsPC(oKiller))
{
AdjustAlignment(oKiller, ALIGNMENT_EVIL, i5);
}
else
{
// If it is a summon, henchmen or familar of a PC, we adust the PC itself
// Clever, eh?
object oMaster = GetMaster(oKiller);
if(GetIsObjectValid(oMaster) && GetIsPC(oMaster))
{
AdjustAlignment(oMaster, ALIGNMENT_EVIL, i5);
}
}
}
// Always shout when we are killed. Reactions - Morale penalty, and attack the killer.
AISpeakString(I_WAS_KILLED);
// Speaks the set death speak, like "AGGGGGGGGGGGGGGGGGGG!! NOOOO!" for instance :-)
SpeakArrayString(AI_TALK_ON_DEATH);
// First check - do we use "destroyable corpses" or not? (default, yes)
if(!GetSpawnInCondition(AI_FLAG_OTHER_TURN_OFF_CORPSES, AI_OTHER_MASTER))
{
// We will actually dissapear after 30.0 seconds if not raised.
int iTime = GetAIInteger(AI_CORPSE_DESTROY_TIME);
if(iTime == i0) // Error checking
{
iTime = i30;
}
// 64: "[Death] Checking corpse status in " + IntToString(iTime) + " [Killer] " + GetName(oKiller) + " [Times Died Now] " + IntToString(iDeathCounterNew)
DebugActionSpeakByInt(64, oKiller, iTime, IntToString(iDeathCounterNew));
// Delay check
DelayCommand(IntToFloat(iTime), DeathCheck(iDeathCounterNew));
}
else
{
/************************ [Alternative Corpses] ********************************
This is where you can add some alternative corpse code - EG looting
and so on, without disrupting the rest of the AI (as the corpses
are turned off).
************************* [Alternative Corpses] *******************************/
// Add alternative corpse code here
/************************ [Alternative Corpses] *******************************/
}
// Signal the death event.
FireUserEvent(AI_FLAG_UDE_DEATH_EVENT, EVENT_DEATH_EVENT);
}
// We need a wrapper. If the amount of deaths, got in this, is not equal to iDeaths,
// we don't execute the script, else we do. :-P
void DeathCheck(int iDeaths)
{
// Do the deaths imputted equal the amount we have suffered?
if(GetAIInteger(AMOUNT_OF_DEATHS) == iDeaths)
{
// - This now includes a check for Bioware's lootable functions and using them.
ExecuteScript(FILE_DEATH_CLEANUP, OBJECT_SELF);
}
}