Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NPCs do not collect the weapon after defeating an opponent #194

Merged
merged 2 commits into from May 8, 2021
Merged

Conversation

szapp
Copy link
Collaborator

@szapp szapp commented Apr 24, 2021

Describe the bug
NPCs do not reliably pick up the weapon of their defeated opponent.

Expected behavior
NPCs now correctly pick up the weapon and ammunition of their defeated opponent.

Steps to reproduce the issue

  1. Attack an NPC.
  2. Get defeated by the NPC in a fight.
  3. The NPC might loot the ore of the PC but not will fail to pick up the weapon.

@pawbuj1981 pawbuj1981 added the validation: required This issue needs validation from one of the validators. label Mar 19, 2021
@szapp szapp changed the title NPC should collect a hero weapon after defeating him ! NPCs do not collect the weapon after defeating an opponent Mar 19, 2021
@szapp
Copy link
Collaborator

szapp commented Mar 19, 2021

Thanks for your contributions! It looks like you chose the wrong issue template (for language/translations bugs). I will try to add the missing details.

It looks like the following function is involved. The item cannot be reliably determined and no weapon will be picked up as a result. It is very similar to #3.

func void ZS_AssessBody_RecoverWeapon ()
{
PrintDebugNpc (PD_ZS_FRAME, "ZS_AssessBody_RecoverWeapon");
B_SetPerception (self);
//-------- nach der evtl. fallengelassenen Waffe suchen --------
Npc_PerceiveAll (self);
if (( Wld_DetectItem (self,ITEM_KAT_NF) || Wld_DetectItem (self,ITEM_KAT_FF) )
&& Npc_GetDistToItem(self,item) < 300 )
{
PrintDebugNpc (PD_ZS_CHECK, "...Nah- oder Fernkampfwaffe gefunden!" );
B_SayOverlay (self, NULL, "$ITakeYourWeapon");
AI_TakeItem (self, item);
AI_EquipBestMeleeWeapon(self);
AI_EquipBestRangedWeapon(self);
};
//-------- Heilen ! --------
AI_StartState (self, ZS_HealSelf, 1, "");
};

The if-condition here is faulty. Both function calls to Wld_DetectItem set the instance item - if not found it will be set to NULL. Therefore it may happen that the condition will not be true. To solve this, it should be confirmed that the byte code of the if-condition looks like here. The if-block should be overwritten with something similar as found here already (with adjusted distance and the additional SVM output):

/*
* This function essentially replaces (not technically!) the function 'B_RegainDroppedWeapon'
*/
func void G1CP_003_RegainDroppedWeapon_Logic(var C_Npc slf) {
Npc_PerceiveAll(slf);
// Define possibly missing symbols locally
const int ITEM_KAT_NF = 1<<1;
const int ITEM_KAT_FF = 1<<2;
const int ITEM_KAT_MUN = 1<<3;
// Melee weapon
if (Wld_DetectItem(slf, ITEM_KAT_NF)) {
if (Npc_GetDistToItem(slf, item) < 300) // Prevent walking off too far
&& (G1CP_NpcCanSeeItemFreeLos(slf, item)) // Does not have to face it, only line of sight
&& (!Npc_HasEquippedMeleeWeapon(slf)) {
AI_TakeItem(slf, item);
AI_Function_NI(slf, EquipWeapon, slf, Hlp_GetInstanceId(item)); // Equip this exact weapon in particular
};
};
// Ranged weapon
if (Wld_DetectItem(slf, ITEM_KAT_FF)) {
if (Npc_GetDistToItem(slf, item) < 300)
&& (G1CP_NpcCanSeeItemFreeLos(slf, item))
&& (!Npc_HasEquippedRangedWeapon(slf)) {
AI_TakeItem(slf, item);
AI_Function_NI(slf, EquipWeapon, slf, Hlp_GetInstanceId(item));
};
};
// Ammunition (just a bonus)
if (Wld_DetectItem(slf, ITEM_KAT_MUN)) {
if (Npc_GetDistToItem(slf, item) < 300)
&& (G1CP_NpcCanSeeItemFreeLos(slf, item)) {
AI_TakeItem(slf, item);
};
};
};

@szapp szapp added compatibility: difficult This issue is difficult to make compatible. provided fix This issue has a fix provided in the comments. impl: modify/analyze script func This issue requires analyzing and/or modifying the bytecode of script functions. type: session fix The fix for this issues is persistent across a session. labels Mar 19, 2021
@szapp szapp self-assigned this Mar 19, 2021
@szapp szapp added this to NPC state in Fix templates Mar 19, 2021
@pawbuj1981
Copy link
Author

pawbuj1981 commented Mar 20, 2021

Here is main condition for that code from my resources,

Maybe it helps to decrease level of incompaitibility !!

if ( Wld_DetectItem (self, ITEM_KAT_NF) 
	{
		**if (Hlp_IsValidItem(item))// this "if" is really new thing !!!**
		{
			if (Npc_GetDistToItem(self,item) < 1000)
			{				
				AI_GotoItem				(self, item);				
				AI_TakeItem	(self, item);				
				B_Say		(self, self, "$ITAKEYOURWEAPON");	

@szapp szapp added the impl: add/modify if-condition This issue requires adding/replacing conditions to if-statements. label Apr 22, 2021
@szapp
Copy link
Collaborator

szapp commented Apr 22, 2021

Suggestion on how to implement it:

  1. Find the if condition in the byte code. Identify it by the function calls to Wld_DetectItem and Npc_GetDistToItem and the conjunctions || and &&, arguments can be neglected.
    //-------- nach der evtl. fallengelassenen Waffe suchen --------
    Npc_PerceiveAll (self);
    if (( Wld_DetectItem (self,ITEM_KAT_NF) || Wld_DetectItem (self,ITEM_KAT_FF) )
    && Npc_GetDistToItem(self,item) < 300 )
    {
  2. Use the G1CP function G1CP_AddIfCondition to check the evaluation of the conditions. This is done by passing a function to G1CP_AddIfCondition that takes one parameter. If that argument is true in our function, properly set the global symbol item by re-running Wld_DetectItem (separately! for ITEM_KAT_NF and ITEM_KAT_FF) and return true to continue into the if-block.
  3. Additionally, the function calls to AI_EquipBestMeleeWeapon and AI_EquipBestRangedWeapon could be replaced to equip explicitly the picked up weapon - given it is stronger than the currently equipped one. This will prevent traders from then suddenly equipping a completely different weapon from their trading inventory, see Vendors equip strongest weapon  #59.

@szapp szapp added this to the v1.2.0 milestone Apr 22, 2021
@szapp szapp added this to To Do in v1.2.0 via automation Apr 22, 2021
@szapp
Copy link
Collaborator

szapp commented Apr 24, 2021

The test is semi-automatic. It is manual, but the success will be displayed on the screen. Failure will be visible from the zSpy.

@szapp szapp moved this from To Do to In Progress in v1.2.0 Apr 24, 2021
@szapp szapp removed their assignment Apr 24, 2021
@szapp szapp removed the impl: add/modify if-condition This issue requires adding/replacing conditions to if-statements. label Apr 24, 2021
@AmProsius AmProsius merged commit 23d1d8d into master May 8, 2021
v1.2.0 automation moved this from In Progress to Done May 8, 2021
@AmProsius AmProsius deleted the bug194 branch May 8, 2021 19:30
@szapp szapp removed the validation: required This issue needs validation from one of the validators. label May 14, 2021
@szapp szapp moved this from Modify NPC state to Some NPC Test? (Todo adjust name) in Fix templates Feb 6, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compatibility: difficult This issue is difficult to make compatible. impl: modify/analyze script func This issue requires analyzing and/or modifying the bytecode of script functions. provided fix This issue has a fix provided in the comments. type: session fix The fix for this issues is persistent across a session.
Projects
Fix templates
NPC manual test (TODO rename)
v1.2.0
  
Done
Development

Successfully merging this pull request may close these issues.

None yet

3 participants