-
Npc_ChangeAttribute not causing instant death.
Howdy, people.
I have a problem of delicate scripting nature. I created a function that's supposed to enable the player to execute a "sneak attack"; it's rather basic, but it works. The code for it is below:
func void CheckForBackstabDamage(var C_Npc other,var C_Npc self)
{
if(C_NpcIsHero(other) && (!Npc_CanSeeNpc(self,other) || Npc_IsInState(self,ZS_Sleep) || Npc_IsInState(self,ZS_Sleep_Deep)) && C_BodyStateContains(other,BS_HIT) && (Npc_GetTalentSkill(other,NPC_TALENT_SNEAK) == TRUE) && Npc_IsInFightMode(other,FMODE_MELEE) && !C_NpcIsUndead(self) && !C_NpcIsGolem(self) && !Npc_IsInState(self,ZS_Attack) && !Npc_IsInState(self,ZS_MM_Attack))
{
Backstab = other.attribute[ATR_DEXTERITY] * 3;
Npc_ChangeAttribute(self,ATR_HITPOINTS,-Backstab);
PrintScreen("Sneak attack!",-1,-1,Font_Screen,2);
if(Npc_IsDead(self))
{
B_GiveDeathXp(other,self);
};
};
};
I took the Npc_ChangeAttribute bit from B_MagicHurtNpc function. It's all dandy and stuff, but if the Backstab value exceeds the victim's current Health, instead of instantly dying, it barks back and only then falls down lifelessly. Sometimes, it even readies their weapon, barks back, and then perishes.
I tried to apply AI_StopProcessInfos(self), or Npc_ClearAIQueue(self), or AI_PlayAni(other,"T_DEAD"), alone and in mixed configurations, but no dice.
Does anyone know how to script it so the victim would simply die when they are supposed to die, with no "Just you wait, sumbitch!" remark before realizing they are dead?
Geändert von Czudak (11.01.2020 um 20:55 Uhr)
-
What do you mean by "exceeds the victim's current Health"? Does that include dealing the exact same damage as their current health? Otherwise you could check if the damage is greater and then set the hp to exactly zero.
How is the sneak attack executed? Is it just a check when performing a normal attack? In that case the check might simply be too late. So the attack is processed and causes the target to draw his weapon and THEN your check happens and he gets killed.
So it would be interesting to know in which file and at which position your function is called.
-
Zitat von Nincompoop
What do you mean by "exceeds the victim's current Health"? Does that include dealing the exact same damage as their current health? Otherwise you could check if the damage is greater and then set the hp to exactly zero.
How is the sneak attack executed? Is it just a check when performing a normal attack? In that case the check might simply be too late. So the attack is processed and causes the target to draw his weapon and THEN your check happens and he gets killed.
So it would be interesting to know in which file and at which position your function is called.
Right. I knew I forgot about something.
I think you might be on something. The backstab check requires the player to be in the "hitting" bodystate [it's C_BodyStateContains(other,BS_HIT) in the function from the first post], and the whole check was inserted into the B_ASSESSDAMAGE script. I will paste it here, via the quote code, so it would be readable better. The call for my "backstab" check is third from the top.
func void B_AssessDamage()
{
if(Hlp_GetInstanceID(self) == Hlp_GetInstanceID(Greg_Nw))
{
if((B_Greg_ComesToDexter_OneTime == TRUE) && Npc_IsPlayer(other) && !Npc_KnowsInfo(other,Dia_Addon_Greg_NW_CaughtDexter) && !Npc_KnowsInfo(other,Dia_Addon_Greg_NW_CaughtDexter2) && !Npc_KnowsInfo(other,Dia_Addon_Greg_NW_WodennNu))
{
return;
};
};
B_ArrowBonusDamage(other,self);
CheckForBackstabDamage(other,self);
if(Npc_IsInState(self,ZS_ReactToDamage))
{
B_Attack(self,other,AR_ReactToDamage,0);
};
if((Hlp_GetInstanceID(self) == Hlp_GetInstanceID(Quarhodron)) || (Hlp_GetInstanceID(self) == Hlp_GetInstanceID(Rhademes)))
{
B_GhostSpecialDamage(other,self);
return;
};
if(Npc_IsPlayer(other) && (self.guild == GIL_FRIENDLY_ORC))
{
B_SetAttitude(self,ATT_HOSTILE);
};
B_BeliarsWeaponSpecialDamage(other,self);
if(self.aivar[AIV_ArenaFight] == AF_AFTER)
{
self.aivar[AIV_ArenaFight] = AF_AFTER_PLUS_DAMAGE;
};
if(self.aivar[AIV_EnemyOverride] == TRUE)
{
if(Hlp_GetInstanceID(self) == Hlp_GetInstanceID(Raven))
{
self.aivar[AIV_EnemyOverride] = FALSE;
Npc_ExchangeRoutine(self,"WaitForPlayer");
Raven_Awaken = TRUE;
};
};
if(Npc_IsInState(self,ZS_Attack))
{
if(Npc_IsPlayer(other) && (self.npcType == NPCTYPE_FRIEND))
{
return;
};
if(Npc_IsPlayer(other) && (self.aivar[AIV_PartyMember] == TRUE))
{
return;
};
if(Hlp_GetInstanceID(other) != self.aivar[AIV_LASTTARGET])
{
if((self.aivar[AIV_HitByOtherNpc] == Hlp_GetInstanceID(other)) || (Hlp_GetInstanceID(other) != Hlp_GetInstanceID(hero)))
{
Npc_SetTarget(self,other);
}
else
{
self.aivar[AIV_HitByOtherNpc] = Hlp_GetInstanceID(other);
};
};
return;
};
if(B_AssessEnemy())
{
return;
};
if(!Npc_IsPlayer(other) && (other.aivar[AIV_ATTACKREASON] == AR_NONE))
{
B_Attack(self,other,AR_NONE,0);
return;
};
if(Npc_IsInFightMode(other,FMODE_MELEE) || Npc_IsInFightMode(other,FMODE_FIST) || Npc_IsInFightMode(other,FMODE_NONE))
{
if((Npc_GetAttitude(self,other) == ATT_FRIENDLY) || ((self.npcType == NPCTYPE_FRIEND) && Npc_IsPlayer(other)))
{
if(!Npc_IsInState(self,ZS_ReactToDamage))
{
Npc_ClearAIQueue(self);
B_ClearPerceptions(self);
AI_StartState(self,ZS_ReactToDamage,0,"");
return;
};
};
};
B_Attack(self,other,AR_ReactToDamage,0);
};
-
hm, seems to be the right place, unless somehow one of the perceiptions get triggered first (fight sound or something) but I doubt it.
You could try adding a check in the B_AssessDamage to see if the NPC HP are 0 and then add a return statement there (return from the B_AssessDamage, not from your own function).
btw: For readability, the code block is better than the quote ('#' - Symbol, or [code][*/code] (without the asterisk)).
-
Hello. Try to make a check on the damage and health of the target, and if the target will die translate it into a state of death
Code:
//old version
func void CheckForBackstabDamage(var C_Npc other,var C_Npc self)
{
if(C_NpcIsHero(other) && (!Npc_CanSeeNpc(self,other) || Npc_IsInState(self,ZS_Sleep) || Npc_IsInState(self,ZS_Sleep_Deep)) && C_BodyStateContains(other,BS_HIT) && (Npc_GetTalentSkill(other,NPC_TALENT_SNEAK) == TRUE) && Npc_IsInFightMode(other,FMODE_MELEE) && !C_NpcIsUndead(self) && !C_NpcIsGolem(self) && !Npc_IsInState(self,ZS_Attack) && !Npc_IsInState(self,ZS_MM_Attack))
{
Backstab = other.attribute[ATR_DEXTERITY] * 3;
Npc_ChangeAttribute(self,ATR_HITPOINTS,-Backstab);
PrintScreen("Sneak attack!",-1,-1,Font_Screen,2);
if(Npc_IsDead(self))
{
B_GiveDeathXp(other,self);
};
};
};
//new version
func void CheckForBackstabDamage(var C_Npc other,var C_Npc self)
{
if(C_NpcIsHero(other) && (!Npc_CanSeeNpc(self,other) || Npc_IsInState(self,ZS_Sleep) || Npc_IsInState(self,ZS_Sleep_Deep)) && C_BodyStateContains(other,BS_HIT) && (Npc_GetTalentSkill(other,NPC_TALENT_SNEAK) == TRUE) && Npc_IsInFightMode(other,FMODE_MELEE) && !C_NpcIsUndead(self) && !C_NpcIsGolem(self) && !Npc_IsInState(self,ZS_Attack) && !Npc_IsInState(self,ZS_MM_Attack))
{
Backstab = other.attribute[ATR_DEXTERITY] * 3;
if(Backstab >= self.attribute[ATR_HITPOINTS])
{
self.attribute[ATR_HITPOINTS] = 0;
PrintScreen("Sneak attack!",-1,-1,Font_Screen,2);
B_GiveDeathXp(other,self);
AI_PlayAniBS(self, "T_DEAD", BS_DEAD);
if(self.guild < GIL_SEPERATOR_HUM)
{
B_Say(self,other,$DEAD);
};
AI_StartState(self,ZS_DEAD,0,"");
}
else
{
Npc_ChangeAttribute(self,ATR_HITPOINTS,-Backstab);
PrintScreen("Sneak attack!",-1,-1,Font_Screen,2);
};
};
};
Wrote in haste, correct errors if that
Geändert von N1kX (12.01.2020 um 09:37 Uhr)
-
Zitat von Nincompoop
hm, seems to be the right place, unless somehow one of the perceiptions get triggered first (fight sound or something) but I doubt it.
You could try adding a check in the B_AssessDamage to see if the NPC HP are 0 and then add a return statement there (return from the B_AssessDamage, not from your own function).
btw: For readability, the code block is better than the quote ('#' - Symbol, or [code][*/code] (without the asterisk)).
Zitat von N1kX
Hello. Try to make a check on the damage and health of the target, and if the target will die translate it into a state of death
Code:
//old version
func void CheckForBackstabDamage(var C_Npc other,var C_Npc self)
{
if(C_NpcIsHero(other) && (!Npc_CanSeeNpc(self,other) || Npc_IsInState(self,ZS_Sleep) || Npc_IsInState(self,ZS_Sleep_Deep)) && C_BodyStateContains(other,BS_HIT) && (Npc_GetTalentSkill(other,NPC_TALENT_SNEAK) == TRUE) && Npc_IsInFightMode(other,FMODE_MELEE) && !C_NpcIsUndead(self) && !C_NpcIsGolem(self) && !Npc_IsInState(self,ZS_Attack) && !Npc_IsInState(self,ZS_MM_Attack))
{
Backstab = other.attribute[ATR_DEXTERITY] * 3;
Npc_ChangeAttribute(self,ATR_HITPOINTS,-Backstab);
PrintScreen("Sneak attack!",-1,-1,Font_Screen,2);
if(Npc_IsDead(self))
{
B_GiveDeathXp(other,self);
};
};
};
//new version
func void CheckForBackstabDamage(var C_Npc other,var C_Npc self)
{
if(C_NpcIsHero(other) && (!Npc_CanSeeNpc(self,other) || Npc_IsInState(self,ZS_Sleep) || Npc_IsInState(self,ZS_Sleep_Deep)) && C_BodyStateContains(other,BS_HIT) && (Npc_GetTalentSkill(other,NPC_TALENT_SNEAK) == TRUE) && Npc_IsInFightMode(other,FMODE_MELEE) && !C_NpcIsUndead(self) && !C_NpcIsGolem(self) && !Npc_IsInState(self,ZS_Attack) && !Npc_IsInState(self,ZS_MM_Attack))
{
Backstab = other.attribute[ATR_DEXTERITY] * 3;
if(Backstab >= self.attribute[ATR_HITPOINTS])
{
self.attribute[ATR_HITPOINTS] = 0;
PrintScreen("Sneak attack!",-1,-1,Font_Screen,2);
B_GiveDeathXp(other,self);
AI_PlayAniBS(self, "T_DEAD", BS_DEAD);
if(self.guild < GIL_SEPERATOR_HUM)
{
B_Say(self,other,$DEAD);
};
AI_StartState(self,ZS_DEAD,0,"");
}
else
{
Npc_ChangeAttribute(self,ATR_HITPOINTS,-Backstab);
PrintScreen("Sneak attack!",-1,-1,Font_Screen,2);
};
};
};
Wrote in haste, correct errors if that
Thank you for your input, fellows! I tried your solutions (combined too), but it didn't work. I need to investigate those "perceptions"; maybe try to disable all perceptions altogether if the requirements for a "sneak attack" happen in the first place, and then calculate the damage and the possibility of death? Or maybe it's not doable with the clean Daedalus and one needs a scripts extender? I will report back once I'm done with pestering people on the other forums!
Berechtigungen
- Neue Themen erstellen: Nein
- Themen beantworten: Nein
- Anhänge hochladen: Nein
- Beiträge bearbeiten: Nein
|