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 cannot use ladders when following the player #136
Conversation
I have a fix for followers specifically. I don't know how to fix it for NPCs in general. gothic-1-community-patch/scriptbase/_work/Data/Scripts/Content/Story/ZS/ZS_FollowPC.d Lines 60 to 69 in 0623f55
changed to func void B_FollowPC_AssessSC()
{
PrintDebugNpc (PD_TA_FRAME, "B_FollowPC_AssessSC");
// Disable this perception when climbing a ladder
if (C_BodyStateContains(self, BS_CLIMB)) {
return;
};
if (Npc_GetDistToNpc(self,hero) < HAI_DIST_FOLLOWPC)
{
PrintDebugNpc (PD_TA_CHECK, "...SC-Meister jetzt nahe genug!");
B_FullStop (self);
};
|
We could just rename the issue. I currently don't know a situation in which an NPC has to climb a latter while they run freely. |
Tried to find a more specific name. (I haven't changed the description of the issue, though.)
Gorn in the Free Mine, for example (again). If he falls down and wants to reach the NPC he is targeting above, he will eventually reach the ladder and climb up. If he is interrupted he will continue to fall down. But I could only reproduce this once. Update I am not so sure how often it would happen that an NPC that is involved in a fight (or otherwise) climbs a ladder. Until we experience that more specifically I would like to leave it at this issue, because I checked and I don't see any way to make it work in general without possibly breaking a mod. |
Just checked that issue a minute ago and it does not works properly . ! I have tested on Gothic 1 vanilla with Pc_FighterFM. Again Gothic Mod Fix team had fixed that. I used their code and little change so I will forward solution soon. |
Here is the code, I believe it needs to modify a bit. Also NPCc react on hero being attacked ! {
PrintDebugNpc(PD_TA_FRAME,"ZS_FollowPC");
Npc_PercEnable(self,PERC_ASSESSENEMY,B_AssessEnemy);
Npc_PercEnable(self,PERC_ASSESSPLAYER,B_FollowPC_AssessSC);
Npc_SetPercTime(self,1);
self.senses = SENSE_SEE | SENSE_HEAR | SENSE_SMELL;
Npc_PercEnable(self,PERC_ASSESSDAMAGE,ZS_ReactToDamage);
Npc_PercEnable(self,PERC_ASSESSCASTER,B_AssessCaster);
Npc_PercEnable(self,PERC_ASSESSMAGIC,B_AssessMagic);
Npc_PercEnable(self,PERC_ASSESSMURDER,ZS_AssessMurder);
Npc_PercEnable(self,PERC_ASSESSDEFEAT,ZS_AssessDefeat);
Npc_PercEnable(self,PERC_ASSESSFIGHTSOUND,B_AssessFightSound);
Npc_PercEnable(self,PERC_ASSESSTALK,B_AssessTalk);
Npc_PercEnable(self,PERC_MOVEMOB,B_MoveMob);
self.aivar[AIV_ITEMFREQ] = 0;
};
func int ZS_FollowPC_Loop()
{
if(C_BodyStateContains(hero,BS_CLIMB) && (self.aivar[AIV_ITEMFREQ] == 0))
{
hero.wp = Npc_GetNearestWP(hero);
self.aivar[AIV_ITEMFREQ] = 1;
AI_SetWalkMode(self,NPC_RUN);
AI_GotoWP(self,hero.wp);
return LOOP_CONTINUE;
}
else if(C_BodyStateContains(hero,BS_CLIMB) && (self.aivar[AIV_ITEMFREQ] == 1))
{
AI_Wait(self,0.5);
return LOOP_CONTINUE;
}
else if(!C_BodyStateContains(hero,BS_CLIMB) && (self.aivar[AIV_ITEMFREQ] == 1))
{
hero.wp = Npc_GetNearestWP(hero);
self.aivar[AIV_ITEMFREQ] = 2;
AI_StopLookAt(self);
AI_SetWalkMode(self,NPC_RUN);
AI_GotoWP(self,hero.wp);
return LOOP_CONTINUE;
}
else if(self.aivar[AIV_ITEMFREQ] == 2)
{
if(C_BodyStateContains(hero,BS_CLIMB))
{
self.aivar[AIV_ITEMFREQ] = 0;
return LOOP_CONTINUE;
}
else if(Npc_GetDistToNpc(self,hero) > 400)
{
self.aivar[AIV_ITEMFREQ] = 1;
return LOOP_CONTINUE;
};
self.aivar[AIV_ITEMFREQ] = 0;
};
//*****************************************************************************
//added by pawbuj
if (self.aivar[AIV_ITEMFREQ] == 0)&&(Check_NpcHangState (hero) == true)
{
//startnpc = Npc_GetNearestWP(self);
AI_Wait(self,4);
//hanged = true;
Npc_SetStateTime(self,0);
//PrintScreen (ConcatStrings (self.name,startnpc),-1,-1,"FONT_OLD_10_WHITE.TGA",5);
return LOOP_CONTINUE;
};
//added by pawbuj
//************************************************************************************
if((self.id == 524) && !self.aivar[AIV_PARTYMEMBER])
{
return LOOP_END;
};
if(C_BodyStateContains(hero,BS_WALK))
{
AI_SetWalkMode(self,NPC_WALK);
}
else if(!C_BodyStateContains(self,BS_SWIM))
{
AI_SetWalkMode(self,NPC_RUN);
};
if(Npc_GetDistToNpc(self,hero) > 300)
{
AI_GotoNpc(self,hero);
}
else if(!C_BodyStateContains(self,BS_CLIMB))
{
B_SmartTurnToNpc(self,hero);
};
return LOOP_CONTINUE;
};
func void ZS_FollowPC_End()
{
PrintDebugNpc(PD_TA_FRAME,"ZS_FollowPC_End");
self.senses = hero.senses;
self.aivar[AIV_ITEMFREQ] = 0;
};
func void B_FollowPC_AssessSC()
{
PrintDebugNpc(PD_TA_FRAME,"B_FollowPC_AssessSC");
if((Npc_GetDistToNpc(self,hero) < 300) && !C_BodyStateContains(self,BS_CLIMB) && !self.aivar[AIV_ITEMFREQ])
{
PrintDebugNpc(PD_TA_CHECK,"...SC-Meister jetzt nahe genug!");
B_FullStop(self);
};
if(Npc_CheckInfo(self,1))
{
PrintDebugNpc(PD_TA_CHECK,"...wichtige Info zu vergeben!");
if(!hero.aivar[AIV_INVINCIBLE])
{
hero.aivar[AIV_IMPORTANT] = TRUE;
B_FullStop(other);
B_FullStop(self);
};
AI_StartState(self,ZS_Talk,0,"");
return;
};
};
func void B_FollowPC_AssessOthersDamage()
{
var C_Npc her;
var C_Npc rock;
her = Hlp_GetNpc(PC_Hero);
rock = Hlp_GetNpc(PC_Rockefeller);
if((Hlp_GetInstanceID(other) == Hlp_GetInstanceID(her)) || (Hlp_GetInstanceID(other) == Hlp_GetInstanceID(rock)))
{
if(!Npc_IsInState(self,ZS_Attack))
{
var string asysta;
asysta = ConcatStrings (self.name," rusza z pomocą!");
PrintScreen ("O", 3,48,"PAWBUJ2.TGA",3);//GOTHIC
PrintScreen (asysta, 9, 50, _STR_FONT_ONSCREEN, 3 );
Npc_ClearAIQueue(self);
Npc_SetTarget(self,victim);
AI_StartState(self,ZS_Attack,0,"");
};
}
else if((Hlp_GetInstanceID(victim) == Hlp_GetInstanceID(her)) || (Hlp_GetInstanceID(victim) == Hlp_GetInstanceID(rock)))
{
asysta = ConcatStrings (self.name," rusza z odsieczą!");
PrintScreen ("O", 3,48,"PAWBUJ2.TGA",3);//GOTHIC
PrintScreen (asysta, 9, 50, _STR_FONT_ONSCREEN, 3 );
Npc_ClearAIQueue(self);
Npc_SetTarget(self,other);
AI_StartState(self,ZS_Attack,0,"");
};
}; |
I looked in my files and found the int func which is necessary to run previous code, now should be working ! func string oCAniCtrl__GetCurrentAniName(var int oCAniCtrl_Ptr)
{
var int hlp;
hlp = MEM_ReadInt(oCAniCtrl_Ptr+104);//zCModel
if(hlp)
{
hlp = MEM_ReadInt(hlp+56);//*ActiveAniLayer1
if(hlp)
{
hlp = MEM_ReadInt(hlp);//*oCAni
if(hlp)
{
return MEM_ReadString(hlp+36); // This will read active ani name(?)
};//aniname(zstring)
};
};
return "ERROR";
};
func int Check_NpcHangState(var C_NPC npc)
{
//var int iswalking; var int isstanding;
var oCNpc _oCNpc;
_oCNpc = hlp_getnpc(npc);
//CALL__thiscall (_oCNpc.anictrl,oCAniCtrl_Human_IsWalking_offset); iswalking = CALL_GetResult();
//CALL__thiscall (_oCNpc.anictrl,oCAniCtrl_Human_IsStanding_offset); isstanding = CALL_GetResult();
var string L1Ani;
// Get Current Ani
L1Ani = oCAniCtrl__GetCurrentAniName(_oCNpc.anictrl);
if (Hlp_StrCmp(L1Ani,"ERROR")) { return false;};
if (Hlp_StrCmp(L1Ani,"T_HANG_2_STAND")) { return true ;};
//|| Ani_BodyStateContains(npc,BS_RUN) )
}; |
You have to wrap your code in three backticks to create a code block. To enable syntax highlighting, append a
I've updated your post accordingly. |
Keep in mind, that the issue here specifically refers to NPCs being interrupted while climbing a ladder and always falling down midway, which - given our testing - is successfully fixed here. There are other cases in which the NPC may still drop, but these are not due to issues with following, but when e.g. the NPC is taking damage. See my notes above:
The NPC may still be running in circles while the player is climbing the ladder, but the issue of the NPCs not being able to use a ladder is sufficiently addressed here already. Thanks for your scripts. They seem to add a some minor improvements to the behavior of the NPC while following. Mostly to make the NPC wait while the player is climbing a ladder, follow immediately and avoid running in circles at the bottom of the ladder. Nevertheless, that does not address the issue discussed here. That may be part of general pathfinding, which we might address from a different angle. |
Describe the bug
NPCs don't use ladders properly when they are following the player.
Expected behavior
NPCs now use ladders properly when they are following the player.
Steps to reproduce the issue
Testing
Run a manual test with
test 136
.Additional context
When Gorn runs off the platform, he struggles to come up again. He starts using the ladder, but falls down midways.