Initial commit
Adding all of the current content for Anphillia Unlimited.
This commit is contained in:
239
_module/nss/j_ai_ondeath.nss
Normal file
239
_module/nss/j_ai_ondeath.nss
Normal file
@@ -0,0 +1,239 @@
|
||||
/*/////////////////////// [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)
|
||||
1.4 - Removed the redudnant notes on the "You have gained 0 experience" message
|
||||
///////////////////////// [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"
|
||||
#include "xp_inc"
|
||||
#include "lgs_inc"
|
||||
#include "creature_inc"
|
||||
|
||||
// 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 nDeaths);
|
||||
|
||||
void main()
|
||||
{
|
||||
// Set Name (Original Name only)
|
||||
creature_SetName(OBJECT_SELF, CREATURE_NAME_DISPLAY_ORIGINAL);
|
||||
|
||||
// If we are set to, don't fire this script at all
|
||||
if(GetAIInteger(I_AM_TOTALLY_DEAD)) return;
|
||||
|
||||
// Pre-death-event. Returns TRUE if we interrupt this script call.
|
||||
if(FirePreUserEvent(AI_FLAG_UDE_DEATH_PRE_EVENT, EVENT_DEATH_PRE_EVENT)) return;
|
||||
|
||||
// Note: No AI on/off check here.
|
||||
|
||||
// Who killed us? (alignment changing, debug, XP).
|
||||
object oKiller = GetLastKiller();
|
||||
// Get a controlled undead's master
|
||||
if(GetLocalString(oKiller, "MY_MASTER_IS") != "")
|
||||
{
|
||||
object oKillerMaster = GetMaster(oKiller);
|
||||
oKiller = oKillerMaster;
|
||||
}
|
||||
|
||||
if (GetLocalInt(GetModule(),"X3_ENABLE_MOUNT_DB")&&GetIsObjectValid(GetMaster(OBJECT_SELF))) SetLocalInt(GetMaster(OBJECT_SELF),"bX3_STORE_MOUNT_INFO",TRUE);
|
||||
|
||||
// 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, 2.0);
|
||||
// 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.
|
||||
|
||||
It is useful to use GetFirstFactionMember (and Next), GiveXPToCreature,
|
||||
GetXP, SetXP, GetChallengeRating (of self) all are really useful.
|
||||
|
||||
Bug note: GetFirstFactionMember/Next with the PC parameter means either ONLY PC,
|
||||
and so NPC henchmen, unless FALSE is used, will not be even recognised.
|
||||
///////////////////////// [Experience] ///////////////////////////////////////*/
|
||||
// Do XP things (Use object "oKiller" for who killed us).
|
||||
xp_GiveXPForKill(OBJECT_SELF, oKiller);
|
||||
|
||||
|
||||
/*/////////////////////// [Experience] ///////////////////////////////////////*/
|
||||
}
|
||||
|
||||
// Note: Here we do a simple way of checking how many times we have died.
|
||||
// Nothing special. Debugging most useful aspect.
|
||||
int nDeathCounterNew = GetAIInteger(AMOUNT_OF_DEATHS);
|
||||
nDeathCounterNew++;
|
||||
SetAIInteger(AMOUNT_OF_DEATHS, nDeathCounterNew);
|
||||
|
||||
// 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 nDeathEffect = GetAIConstant(AI_DEATH_VISUAL_EFFECT);
|
||||
|
||||
// Valid constants from 0 and up. Apply to our location (not to us, who will go!)
|
||||
if(nDeathEffect >= 0)
|
||||
{
|
||||
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, EffectVisualEffect(nDeathEffect), GetLocation(OBJECT_SELF));
|
||||
}
|
||||
// Default Commoner alignment changing. (If the commoner is not evil!)
|
||||
if(GetLevelByClass(CLASS_TYPE_COMMONER) > 0 &&
|
||||
GetAlignmentGoodEvil(OBJECT_SELF) != ALIGNMENT_EVIL &&
|
||||
!GetSpawnInCondition(AI_FLAG_OTHER_NO_COMMONER_ALIGNMENT_CHANGE, AI_OTHER_MASTER))
|
||||
{
|
||||
if(GetIsPC(oKiller))
|
||||
{
|
||||
AdjustAlignment(oKiller, ALIGNMENT_EVIL, 5);
|
||||
}
|
||||
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, 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Always shout when we are killed. Reactions - Morale penalty, and
|
||||
// attack the killer.
|
||||
AISpeakString(AI_SHOUT_I_WAS_KILLED);
|
||||
|
||||
// Speaks the set death speak, like "AGGGGGGGGGGGGGGGGGGG!! NOOOO!" for instance :-)
|
||||
// Note for 1.4: No need for "CanSpeak()" for this, of course.
|
||||
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 nTime = GetAIInteger(AI_CORPSE_DESTROY_TIME);
|
||||
if(nTime == 0) // Error checking
|
||||
{
|
||||
nTime = 30;
|
||||
}
|
||||
// 64: "[Death] Checking corpse status in " + IntToString(nTime) + " [Killer] " + GetName(oKiller) + " [Times Died Now] " + IntToString(nDeathCounterNew)
|
||||
DebugActionSpeakByInt(64, oKiller, nTime, IntToString(nDeathCounterNew));
|
||||
// Delay check
|
||||
DelayCommand(IntToFloat(nTime), DeathCheck(nDeathCounterNew));
|
||||
}
|
||||
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
|
||||
if(GetRacialType(OBJECT_SELF)==RACIAL_TYPE_ANIMAL)
|
||||
{
|
||||
SetIsDestroyable(FALSE, FALSE, TRUE);
|
||||
DelayCommand(30.0,SetIsDestroyable(TRUE, FALSE, TRUE));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get the location of the dead monster
|
||||
location lCorpseLoc = GetLocation(OBJECT_SELF);
|
||||
|
||||
// Make the corpse NOT fade
|
||||
SetIsDestroyable(FALSE, TRUE, FALSE);
|
||||
|
||||
// Create Blood Stain under the coprse
|
||||
object oBlood = CreateObject(OBJECT_TYPE_PLACEABLE, "plc_bloodstain", lCorpseLoc, FALSE);
|
||||
|
||||
// Create Loot Container on the corpse
|
||||
object oLootObject = CreateObject(OBJECT_TYPE_PLACEABLE, "invis_corpse_obj", lCorpseLoc, FALSE, GetTag(OBJECT_SELF));
|
||||
SetName(oLootObject, "Dead " + GetName(OBJECT_SELF));
|
||||
SetDescription(oLootObject, GetDescription(OBJECT_SELF));
|
||||
|
||||
// Create Loot
|
||||
if ((GetStandardFactionReputation(STANDARD_FACTION_HOSTILE, OBJECT_SELF) >= 90) // Only Faction Hostile creatures will drop stuff
|
||||
//|| FindSubString(GetName(OBJECT_SELF), "Kobold") >= 0 // HACK! Make kobolds drop loot too!
|
||||
|| FindSubString(GetName(OBJECT_SELF), "Spider") >= 0) // HACK! Make spiders drop loot too!
|
||||
{
|
||||
int nMinLoot = GetLocalInt(OBJECT_SELF, CS_LGS_LOOT_MINITEMS);
|
||||
if (nMinLoot == 0)
|
||||
nMinLoot = -1;
|
||||
|
||||
object oContainer = GetNearestObjectByTag(CS_LGS_CHEST_VAR_RESREF, OBJECT_SELF);
|
||||
if (!GetIsObjectValid(oContainer))
|
||||
{
|
||||
lgs_CreateLoot(OBJECT_SELF, oLootObject, OBJECT_INVALID, FALSE, nMinLoot);
|
||||
}
|
||||
else
|
||||
{
|
||||
lgs_CreateLoot(OBJECT_SELF, oContainer, oLootObject, FALSE, nMinLoot);
|
||||
|
||||
// Inform the Loot Container to (re)start it's countdown
|
||||
if (GetLocalInt(oContainer, CS_LGS_CHEST_CHECK_ISCHECKING))
|
||||
SetLocalInt(oContainer, CS_LGS_CHEST_CHECK_COUNT, 1);
|
||||
else
|
||||
ExecuteScript("lgs_chest_check", oContainer);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if there's anything in the loot container
|
||||
if (!GetIsObjectValid(GetFirstItemInInventory(oLootObject)))
|
||||
DestroyObject(oLootObject);
|
||||
|
||||
// Plan for everything to decay
|
||||
float fFade = 240.0f;
|
||||
object oModule = GetModule();
|
||||
ActionWait(fFade);
|
||||
DelayCommand(fFade, lgs_ClearInventory(oLootObject));
|
||||
DelayCommand(fFade, lgs_ClearInventory(OBJECT_SELF));
|
||||
DelayCommand(fFade + 0.1f, DestroyObject(oLootObject));
|
||||
DelayCommand(fFade + 0.1f, DestroyObject(oBlood));
|
||||
DelayCommand(fFade + 0.3f, SetIsDestroyable(TRUE,TRUE,FALSE));
|
||||
DelayCommand(fFade + 0.5f, DestroyObject(OBJECT_SELF));
|
||||
}
|
||||
|
||||
/************************ [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 nDeaths)
|
||||
{
|
||||
// Do the deaths imputted equal the amount we have suffered?
|
||||
if(GetAIInteger(AMOUNT_OF_DEATHS) == nDeaths)
|
||||
{
|
||||
// - This now includes a check for Bioware's lootable functions and using them.
|
||||
ExecuteScript(FILE_DEATH_CLEANUP, OBJECT_SELF);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user