The Jonster wrote: Fri Dec 15, 2023 9:17 pm
PluMGMK wrote: Wed Dec 13, 2023 11:49 am
I guess someone could try to analyse his code in Raymap? I might have a look tonight...
Ooh, whenever you do, lemme know what your results bring up!
Thanks for reminding me, I would have completely forgotten otherwise!
Basically, it is NOT random: Razoff will always choose the direction that moves him furthest away from Rayman. So because Cut jumped to the
left before shooting, Razoff ran to the
right. The rest of the post is technical detail that you don't have to read if you don't want to…
EDIT: I guess it's kinda obvious really, and Cut probably knew this already

But hey, at least now we can see it for definite in the code
OK, so I realized that simply reading the code wasn't going to get me very far, since there was basically no way for me to find out the relevant script entries

So I spent much of the afternoon trying to figure out how to get a live report of what behaviour he was in while playing the level. I don't know if it's because I'm a little rusty at reverse engineering / debugging, or just because the levels of indirection in this engine always tie my mind up in knots, but I feel it took way longer than it should have to come up with the right GDB commands to do this
Code: Select all
# In GDB, to watch the comport of superobject 0x050B6BBC, do
print/x *(*(*(*(0x050B6BBC+4)+0xc))+4)+8 # This establishes the location of the pointer to the current behaviour
watch *(int*)$ # This sets a watchpoint at that location to alert the debugger when the behaviour changes
commands
silent # This suppresses the usual notification message when the watchpoint is hit
printf "Now in behaviour %d\n", (*(*(*(*(*(0x050B6BBC+4)+0xc))+4)+8) - *(*(*(*(*(*(*(0x050B6BBC+4)+0xc))+4)))))/0xc # This prints our own message, subtracting the behaviour base pointer (from the AI model) from the current behaviour and dividing by 12 (the size of the behaviour structure)
c # This automatically continues the game so it is not interrupted after the message is printed
end
From this I determined that behaviour 13 is the one where Razoff stands in the corridor shooting at Rayman, and behaviour 5 is the one where he runs away. So, the relevant code would appear to be the transition from 13 to 5. I found the relevant script using Raymap fairly quickly, and here it is with a few comments I added myself:
Code: Select all
// Waypoint_27 = next waypoint, Waypoint_28 = current waypoint, Waypoint_30 = previous waypoint
ChangePersoSighting(((YLT_RaymanModel)GetPerso("Rayman")).Position() - Position());
Float_12 = AbsoluteValue(GetNormalSlopeVectorAndAngle(Orientation(), ((YLT_RaymanModel)GetPerso("Rayman")).Position() - Position(), 0));
RotateModuleAroundX(unknown, Float_12);
Float_34 = DistanceXYToPerso(((YLT_RaymanModel)GetPerso("Rayman")));
if (IsInAction(Razoff.Action[13]) && CheckActionEnd() || Float_34 < 15f)
{
ChangeAction(Razoff.Action[4]);
Int_37 = NetworkAllocateGraphToMSWay(Graph_0, CrossProduct(5), WayPoint_28, 2);
WayPoint_27 = NetworkNextWPOfType(Graph_0, 0, CrossProduct(5), Nowhere, Nowhere, -Orientation()); // MINUS "Orientation()" => run AWAY!
ChangePersoSighting(GetWPAbsolutePosition(WayPoint_27) - Position());
WayPoint_30 = WayPoint_28;
ReinitCollider();
Int_16 = GetTime();
Float_43 = 10;
Int_21 = (GetTime() - 1500);
SetActionReturn(1);
ChangeMyComport(NIN_m_Razoff.Intelligence[5]); // Start "running away" behaviour
}
This is the first script entry in Razoff's behaviour 13, and it handles both making him face Rayman continuously, and making him run away if Rayman hurts him or gets within 15 length units (centimetres?) of him.
The first line of code, "ChangePersoSighting", ensures that Razoff is always facing Rayman while this behaviour is running, which is important.
The "If" statement handles making him run away if Rayman is too close. The line beginning with "WayPoint_27" is the one where he chooses which node to run to. I'm not 100% sure what the arguments represent, but it is important to note that one of them is "-Orientation()". The minus sign means that this gives a vector which is the exact opposite direction to the one he's facing in. Because of the "ChangePersoSighting" line, this means it always points directly away from Rayman.
Then the game's code goes through the nearest nodes on Graph_0. As far as I can tell, the relevant nodes are the three highlighted in orange here:
Presumably, it gets the vector distance from Razoff to each possible node, and picks whichever one makes the smallest angle with the "-Orientation()" vector. If Rayman is to his left, that will always be the node to the right, and vice versa. It will never be the node at the bottom of the picture, because that would involve running
towards Rayman!
Anyway, I'm a bit tired at the moment and frazzled from trying to figure out what code to look at (as mentioned above) so this post may not be the most coherent

Let me know if anything is unclear / makes no sense…