PDA

View Full Version : Detecting if your interacting with an Npc



thatOneGuyWithTheFace
08-28-2015, 06:59 AM
Is there a standard way for detecting if you're interacting with an npc with Reflection? this code acts exactly how I expect it would... But it crashes after about 30 seconds of use...:mad:

program new;
{$DEFINE SMART}
{$i Reflection/Reflection.simba}

var
xOffset,yOffset: integer;
ChickenBox: TBox;
MyPlayer: TReflectLocalPlayer;
Chicken: TReflectNpc;
ChickenPoint: TPoint;
Players: TReflectPlayerArray;
Timer: TReflectTimer;
smartWidth := 765;
smartHeight := 502;
Npcs: TReflectNpcArray;
InteractingNpc: TReflectNpc;
NullNpc: TReflectNpc;
InteractingName: String;
i,defxp,strxp,attxp: Integer;

//================================~LogicLoop~======= ============================
procedure LogicLoop
begin
Npcs.GetAll;
Npcs.Sort;

// code for checking if the npc is null
InteractingNpc := NullNpc;
MyPlayer.GetInteractingNpc(InteractingNpc);
InteractingName := InteractingNpc.GetName();
writeln(interactingnpc);


for i := 0 to High(Npcs) do
begin
attxp := MyPlayer.GetSkillExp(0);
defxp := MyPlayer.GetSkillExp(1);
strxp := MyPlayer.GetSkillExp(2);
if(Npcs[i].GetName = 'Chicken') and not (Npcs[i].IsUnderAttack)then
begin
//writeln(MyPlayer.GetSkillExp(2));
//writeln(MyPlayer.GetAnimation());
ChickenPoint := Npcs[i].GetMSPoint;
Exit;
end;
end;


end;
//================================~Fin~============= ============================
//================================~GraphicLoop~===== ============================
procedure GraphicLoop
begin
{
//Chicken Loop *START*
if(Chicken.Find('Chicken'))then
begin

//Get Chicken's Location
ChickenPoint := Chicken.GetMSPoint;
}
//Check if Chicken is within smart window Bounds
if(ChickenPoint.x > 0) and (chickenPoint.x < smartWidth)
and(ChickenPoint.y > 0) and (chickenPoint.y < smartHeight) then

begin
Reflect.Smart.Graphics.Clear;
Reflect.Smart.Graphics.DrawBox(5,5,ChickenPoint.x, ChickenPoint.y,false);
Reflect.Smart.Graphics.DrawClippedText('Chicken',' SmallChars',ChickenPoint);
end;
//Chicken Loop *FINISH*




end;
//================================~Fin~============= ============================
//============================AI Input Loop=====================================
procedure AiInputLoop
begin

if not(MyPlayer.IsUnderAttack) and (InteractingName = '')
and not (Chicken.IsUnderAttack) then // and not(MyPlayer.IsAnimating) then
begin
Reflect.Mouse.Move(ChickenPoint,2,2);
Reflect.Mouse.Click(1);
end;






end;
//================================~Fin~============= ============================
//===========================~***MAIN_START***~===== ============================
begin

Reflect.Setup;
MyPlayer.UserName := '*************';
MyPlayer.Password := '*************';
MyPlayer.Active := true;
MyPlayer.Login;

repeat
LogicLoop;
GraphicLoop;
AiInputLoop;
until(false);






end.
//===========================~***MAIN_FIN***~======= ============================
//================================================== ==========================//
//================================================== ==========================//
//================================================== ==========================//
//================================================== ==========================//

ineedbot
08-28-2015, 07:08 AM
I think the problem is here
procedure AiInputLoop
begin

if not(MyPlayer.IsUnderAttack) and (InteractingName = '')
and not (Chicken.IsUnderAttack) then // and not(MyPlayer.IsAnimating) then
begin
Reflect.Mouse.Move(ChickenPoint,2,2);
Reflect.Mouse.Click(1);
end;
The Chicken.IsUnderAttack seems to be checking a null npc. Which I think would crash smart.

Take note of this;
If you grab a npc reference via npc.get or npc.getall etc. you should grab all data needed and store into a variable. Because if you try to get an npc reference again (even different variable), if you try grab data from the first npc reference, it will crash smart.

cosmasjdz
08-28-2015, 07:12 AM
if(Npcs[i].GetName =

Here your crash probably begins :D If reflection finds NO npcs then it cant access npcs[0] and crash happens, make check if length(npcs)>0 before doing this.


if length(npcs)>0 then
begin
for i := 0 to High(Npcs) do
begin
attxp := MyPlayer.GetSkillExp(0);
defxp := MyPlayer.GetSkillExp(1);
strxp := MyPlayer.GetSkillExp(2);
if(Npcs[i].GetName = 'Chicken') and not (Npcs[i].IsUnderAttack)then
begin
//writeln(MyPlayer.GetSkillExp(2));
//writeln(MyPlayer.GetAnimation());
ChickenPoint := Npcs[i].GetMSPoint;
Exit;
end;
end;
end;

Also Ineedbot is right, and there is another issue

procedure AiInputLoop
begin

if not(MyPlayer.IsUnderAttack) and (InteractingName = '')
and not (Chicken.IsUnderAttack) then // and not(MyPlayer.IsAnimating) then
begin
Reflect.Mouse.Move(ChickenPoint,2,2);
Reflect.Mouse.Click(1);
end;

What if chickenpoint is out of bounds? it would crash simba too. Should check like
if pointInBox(inttobox(3,3,whateverx-3,whatevery-3),chickenpoint) then Reflect.Mouse.Move(ChickenPoint,2,2);

And: what if chickenpoint.x is like 1 and it tries to draw box 5x5?. In this case it would need to draw on -4 or so it can crash too. In my eyes it should look like this:

if(ChickenPoint.x > 5) and (chickenPoint.x < (smartWidth-5))
and(ChickenPoint.y > 5) and (chickenPoint.y < (smartHeight-5)) then

begin
Reflect.Smart.Graphics.Clear;
Reflect.Smart.Graphics.DrawBox(5,5,ChickenPoint.x, ChickenPoint.y,false);
Reflect.Smart.Graphics.DrawClippedText('Chicken',' SmallChars',ChickenPoint);
end;

By the way what type of crash do you get? Out of bounds? Color? Acces violation?

thatOneGuyWithTheFace
08-28-2015, 07:36 AM
Thanks cosmasjdz! I'm almost sure you just pointed out the problem... when I isolated that for loop the crash persisted... going to try that that that fix now
As for the out of bounds crash... I encountered that alot earlier and added a failsafe.(it might be a bit obscure or commented out in the code I posted) good eye though.

As for the Crash report: there is none... simba keeps running but Smart shuts down.

Something to Note About writeln(interactingnpc);
returns '' when I log in
returns 'Chicken' as soon as I attack a chicken
returns 'Tool Leprechaun' when smart crashes <<< this only happens when the for loop is included in the code... at least as far as I've tested...

cosmasjdz
08-28-2015, 07:47 AM
your mainloop may be tooagressive. I have had random crashed like that cause of excessive looping, add some waits

repeat
LogicLoop;
wait(10);
GraphicLoop;
wait(10);
AiInputLoop;
wait(10);
until(false);

About leprechaun, interesting one, but personally i dont use names, i just use ids instead and no problems.

ineedbot
08-28-2015, 07:54 AM
It crashes SMART because its trying to access something null'd in reflection. Its how the memory management works with the include.

You gotta use the npc.getName, npc.getID, etc all you can before you call npc.get, npc.getall once more. Because if you try to access the 'outdated' npc, it will crash.

The problem isn't aggressive threading. It shouldn't crash because of it.

cosmasjdz
08-28-2015, 08:02 AM
Just maybe:

InteractingNpc: TReflectNpc;
NullNpc: TReflectNpc;
InteractingName: String;
i,defxp,strxp,attxp: Integer;

//================================~LogicLoop~======= ============================
procedure LogicLoop
begin
Npcs.GetAll;
Npcs.Sort;

// code for checking if the npc is null
InteractingNpc := NullNpc; //assigning value between 2 treflectnpc, why? Maybe assigns nonexisting npc here or whatever?
MyPlayer.GetInteractingNpc(InteractingNpc);
InteractingName := InteractingNpc.GetName();
writeln(interactingnpc);

atleast for me it looks strange approach

thatOneGuyWithTheFace
08-28-2015, 09:07 AM
Anyone know how to reset a TReflectNpc to null/its original state? ...After much digging I found this....Reflect.Smart.IsNull(InteractingNpc.Refere nce) still have problems though.


Simplified the Code to isolate the problem:
begin
Npcs.GetAll;
Npcs.Sort;

MyPlayer.GetInteractingNpc(InteractingNpc);

if(Reflect.Smart.IsNull(InteractingNpc.Reference)) then
begin
writeln('nullNpc');
end;
if(Reflect.Smart.IsNull(InteractingNpc.Reference)) then
begin
writeln(InteractingNpc.GetName);
// InteractingNpc.reference = null; // this "should" work but also ends up crashing the program...
// the problem comes here where I want to completely destroy/reset/null InteractingNpc...
// if I dont then InteractingNpc will remain with a grabage pointer and attempts to be accessed...
// which ends up crashing the program
end;

thatOneGuyWithTheFace
08-28-2015, 10:22 AM
================================================== ===========[SOLUTION]================================================== ================================================== ===============================================




SHORT STORY : Below is some code that returns the string of the current npc you are interacting with. (using the reflection library)

LONG STORY : I basically had to dredge through some trial and error... and alot of searching through the reflection library...
I ended up writing my own deconstructor for the TReflectNpc variable (for some reason this doesnt already exist in the standard reflection library).
... The result is a function you can put in a repeat while false loop and it gives you the string of the npc you're interacting with!!! Oh and did I mention it doesn't crash? (also no random tool leperchauns lol)


program new;
{$DEFINE SMART}
{$i Reflection/Reflection.simba}

var
xOffset,yOffset: integer;
ChickenBox: TBox;
MyPlayer: TReflectLocalPlayer;
Chicken: TReflectNpc;
ChickenPoint: TPoint;
Players: TReflectPlayerArray;
smartWidth := 765;
smartHeight := 502;
Npcs: TReflectNpcArray;
InteractingNpc: TReflectNpc;
NullNpc: TReflectNpc;
InteractingName: String;
i,defxp,strxp,attxp: Integer;
//================================~LogicLoop~======= ============================
procedure LogicLoop
begin
Npcs.GetAll;
Npcs.Sort;

// finds chickens near the player
//if (length(Npcs) > 0) then
//begin
for i := 0 to High(Npcs) do
begin
if(Npcs[i].GetName = 'Chicken') and not (Npcs[i].IsUnderAttack)then
begin
writeln('still checkin for chicken');
ChickenPoint := Npcs[i].GetMSPoint;
Exit;
end;
end;
//end;











//===========================Working Code Starts Here=========================================



// sets 'InteractingNpc' to reference the npc that the player is interacting with
MyPlayer.GetInteractingNpc(InteractingNpc);

if(Reflect.Smart.IsNull(InteractingNpc.Reference)) then // checks if InteractingNpc is null
begin
writeln('nullNpc'); // for debuging
InteractingName := ''; // set name to null
end;



if not(Reflect.Smart.IsNull(InteractingNpc.Reference) )then // checks if InteractingNpc is not null
begin
writeln(InteractingNpc.GetName); // shows you the name in debug window
InteractingName := InteractingNpc.GetName; // stores it in a string

// Deconstructing the InteractingNpc variable
InteractingNpc._Tile := Point(0,0); // then deconstructs the npc variable so it cant be accessed
InteractingNpc._Index := 0;
InteractingNpc._DefReference := 0;
InteractingNpc.reference := 0;
// Deconstructing complete

end;



//==============================Working Code Ends Here==========================







end;
//================================~Fin~============= ============================
//================================~GraphicLoop~===== ============================
procedure GraphicLoop
begin

// if the x and y are within the client's bounds
if(ChickenPoint.x > 0) and (chickenPoint.x < smartWidth)
and(ChickenPoint.y > 0) and (chickenPoint.y < smartHeight) then

// then clear the last drawn objects... and draw the new ones.
begin
Reflect.Smart.Graphics.Clear;
Reflect.Smart.Graphics.DrawBox(5,5,ChickenPoint.x, ChickenPoint.y,false);
Reflect.Smart.Graphics.DrawClippedText('Chicken',' SmallChars',ChickenPoint);
end;




end;
//================================~Fin~============= ============================
//============================AI Input Loop=====================================
procedure AiInputLoop
begin
{
if not(MyPlayer.IsUnderAttack) and (InteractingName = '')
and not (Chicken.IsUnderAttack) then // and not(MyPlayer.IsAnimating) then
begin
Reflect.Mouse.Move(ChickenPoint,2,2);
Reflect.Mouse.Click(1);
end;
}






end;
//================================~Fin~============= ============================
//===========================~***MAIN_START***~===== ============================
begin

Reflect.Setup;
MyPlayer.UserName := '***********';
MyPlayer.Password := '***********';
MyPlayer.Active := true;
MyPlayer.Login;

repeat
LogicLoop;
//GraphicLoop;
//AiInputLoop;
until(false);






end.
//===========================~***MAIN_FIN***~======= ============================
//================================================== ==========================//
//================================================== ==========================//
//================================================== ==========================//
//================================================== ==========================//

I posted because I know some people are going to come to this thread looking for the solution... happy Friday everyone :spot:
Have to go to work... will clean up and make it more readable /functional when I get back

Fitta
08-28-2015, 12:14 PM
================================================== ===========[SOLUTION]================================================== ================================================== ===============================================




SHORT STORY : Below is some code that returns the string of the current npc you are interacting with. (using the reflection library)

LONG STORY : I basically had to dredge through some trial and error... and alot of searching through the reflection library...
I ended up writing my own deconstructor for the TReflectNpc variable (for some reason this doesnt already exist in the standard reflection library).
... The result is a function you can put in a repeat while false loop and it gives you the string of the npc you're interacting with!!! Oh and did I mention it doesn't crash? (also no random tool leperchauns lol)


program new;
{$DEFINE SMART}
{$i Reflection/Reflection.simba}

var
xOffset,yOffset: integer;
ChickenBox: TBox;
MyPlayer: TReflectLocalPlayer;
Chicken: TReflectNpc;
ChickenPoint: TPoint;
Players: TReflectPlayerArray;
smartWidth := 765;
smartHeight := 502;
Npcs: TReflectNpcArray;
InteractingNpc: TReflectNpc;
NullNpc: TReflectNpc;
InteractingName: String;
i,defxp,strxp,attxp: Integer;
//================================~LogicLoop~======= ============================
procedure LogicLoop
begin
Npcs.GetAll;
Npcs.Sort;

// finds chickens near the player
//if (length(Npcs) > 0) then
//begin
for i := 0 to High(Npcs) do
begin
if(Npcs[i].GetName = 'Chicken') and not (Npcs[i].IsUnderAttack)then
begin
writeln('still checkin for chicken');
ChickenPoint := Npcs[i].GetMSPoint;
Exit;
end;
end;
//end;











//===========================Working Code Starts Here=========================================



// sets 'InteractingNpc' to reference the npc that the player is interacting with
MyPlayer.GetInteractingNpc(InteractingNpc);

if(Reflect.Smart.IsNull(InteractingNpc.Reference)) then // checks if InteractingNpc is null
begin
writeln('nullNpc'); // for debuging
InteractingName := ''; // set name to null
end;



if not(Reflect.Smart.IsNull(InteractingNpc.Reference) )then // checks if InteractingNpc is not null
begin
writeln(InteractingNpc.GetName); // shows you the name in debug window
InteractingName := InteractingNpc.GetName; // stores it in a string

// Deconstructing the InteractingNpc variable
InteractingNpc._Tile := Point(0,0); // then deconstructs the npc variable so it cant be accessed
InteractingNpc._Index := 0;
InteractingNpc._DefReference := 0;
InteractingNpc.reference := 0;
// Deconstructing complete

end;



//==============================Working Code Ends Here==========================







end;
//================================~Fin~============= ============================
//================================~GraphicLoop~===== ============================
procedure GraphicLoop
begin

// if the x and y are within the client's bounds
if(ChickenPoint.x > 0) and (chickenPoint.x < smartWidth)
and(ChickenPoint.y > 0) and (chickenPoint.y < smartHeight) then

// then clear the last drawn objects... and draw the new ones.
begin
Reflect.Smart.Graphics.Clear;
Reflect.Smart.Graphics.DrawBox(5,5,ChickenPoint.x, ChickenPoint.y,false);
Reflect.Smart.Graphics.DrawClippedText('Chicken',' SmallChars',ChickenPoint);
end;




end;
//================================~Fin~============= ============================
//============================AI Input Loop=====================================
procedure AiInputLoop
begin
{
if not(MyPlayer.IsUnderAttack) and (InteractingName = '')
and not (Chicken.IsUnderAttack) then // and not(MyPlayer.IsAnimating) then
begin
Reflect.Mouse.Move(ChickenPoint,2,2);
Reflect.Mouse.Click(1);
end;
}






end;
//================================~Fin~============= ============================
//===========================~***MAIN_START***~===== ============================
begin

Reflect.Setup;
MyPlayer.UserName := '***********';
MyPlayer.Password := '***********';
MyPlayer.Active := true;
MyPlayer.Login;

repeat
LogicLoop;
//GraphicLoop;
//AiInputLoop;
until(false);






end.
//===========================~***MAIN_FIN***~======= ============================
//================================================== ==========================//
//================================================== ==========================//
//================================================== ==========================//
//================================================== ==========================//

I posted because I know some people are going to come to this thread looking for the solution... happy Friday everyone :spot:
Have to go to work... will clean up and make it more readable /functional when I get back

It crashes because you cluster up the memory. You can't use a NPC variable within two functions at once as it'll cluster it up when you use .Get functions. If you don't believe me I can show you parts of my Zulrah script, it does not crash :)

Kyle
08-28-2015, 12:24 PM
....

Well, I'll give you credit for definitely trying!
But it seems as if you're missing a few points with reflection, and how the include handles it.. This is a short snip of what you are trying to do:

program Example;
{$DEFINE SMART}
{$i Reflection/Reflection.simba}


var
LocPlayer: TReflectLocalPlayer;
InteractingNpc: TReflectNpc;

begin
Reflect.Setup;
LocPlayer.Create;
repeat
if LocPlayer.GetInteractingIndex <> -1 then //then we are interacting
begin
LocPlayer.GetInteractingNpc(InteractingNpc); //Grab what we are interacting
WriteLn(InteractingNpc.GetName);
end;
Wait(200);
until(False);
end.

You don't have to "deconstruct" anything, which BTW setting everything to 0 isn't deconstructing anything and will actually cause it to crash later because you're setting both reference pointers to 0, which when the include tries to free them later on, will not work as 0 is undefined in memory. What the others were saying about how it crashes is this:


program Example;
{$DEFINE SMART}
{$i Reflection/Reflection.simba}


var
LocPlayer: TReflectLocalPlayer;
Npc1, Npc2: TReflectNpc;
Temp: string;

begin
Reflect.Setup;
LocPlayer.Create;

Npc1.Find('Guard');
Temp := Npc1.GetName;
Npc2.Find('Banker'); //This Free's Npc1, you can NOT access Npc1 now

WriteLn(Npc1.GetName); //Will eventually crash SMART
WriteLn(Npc2.GetName); //Totally fine
WriteLn(Temp); //Fine as well ofc..
end.


This is of course a negative about the way the include is set up, but it was either this, or have NO internal freeing of memory and rely on the scripter for that, but that would cause massive memory leaks all too often.

This is why java and other languages are much better for this type of stuff, since they have built in destructors that will be called whenever you leave the scope of the variable, so you don't ever have to worry about freeing anything.

thatOneGuyWithTheFace
08-28-2015, 04:11 PM
You don't have to "deconstruct" anything, which BTW setting everything to 0 isn't deconstructing anything and will actually cause it to crash later because you're setting both reference pointers to 0, which when the include tries to free them later on, will not work as 0 is undefined in memory. What the others were saying about how it crashes is this:


Hey. On lunch break here.
Argh... I can't believe I didn't think to look at LocalPlayer.GetInteractingIndex when I was going through the include! Must've not had enough sleep haha. Anyways, thank you so much for all the replies...So Great. I didn't expect so many. I think this will definitely help any fellow script-noobs trying their hand at reflection as well... @Elfyyy For that well worded, straight to the point, useful explanation... thank you. Also apologies for under-estimating the completeness of the reflection library. Some false assumptions were made there. Again, To Elfyyy and everyone who replied...this saved me hours of of future bugs and debugging. Thanks!