SRL Archive - Reflection Development

Restructured NPCs.simba


mormonman

2010-12-30 17:17:03

I changed a lot. I added the ability to search for multiple variants(ex. GetNPCMulti('Guard', 823, 'Monkey');). I combined GetNPCs and GetNPCsNull to one function that has a parameter.
The affected files are: Prison, Certer, Gravedigger, Frog, Mime, Demon, Forester, and Sandwich. I have already changed them all, and I uploaded them here:
http://upit.cc/files/d7fe2389.rar

PLEASE VOICE YOUR OPINION ON THIS CHANGE!!!

New NPCs.simba :
//------------------------------------------------------------------\\
//-- Simba Reflection Library --||
//-- NPCs Routines --||
//------------------------------------------------------------------//

//--- Records --//
type
{Holds information related to an NPC}
TNPC = record
Index, ID, Level, Animation, Height, HPRatio, Interacting,
Orientation: integer;// SOUTH = 0; NORTH = 180; CLOCKWISE.
Tile: TTile;
Pixel: TPoint;//Pixel position on tile
Name: String;
Actions: TStringArray;
Moving, Fighting: boolean;
end;

{Array of TNPC}
TNPCArray = array of TNPC;


{*******************************************************************************
function NULL_NPC: TNPC;
Description: Nulls a TNPC
*******************************************************************************}
function NULL_NPC: TNPC;
begin
Result.Index := NULL_INT;
Result.ID := NULL_INT;
Result.Name := NULL_STRING;
Result.Actions := [];
Result.Tile := NULL_TILE;
Result.Moving := False;
Result.Animation := NULL_INT;
Result.Height := NULL_INT;
Result.HPRatio := NULL_INT;
Result.Fighting := False;
Result.Orientation := NULL_INT;
Result.Level := NULL_INT;
Result.Interacting := NULL_INT;
end;

{*******************************************************************************
function _GetNPCActionArray(NPCDef: integer): TStringArray;
By: Drags111
Description: Gets the Action (String) Array according to the NPC Def.
Used in GetNPC functions
*******************************************************************************}
function _GetNPCActionArray(NPCDef: integer): TStringArray;
var
i, c, bytes: integer;
begin
SetLength(Result, 11);
c := 0;
for i := 0 to 10 do
begin
bytes := SmartGetFieldArrayObject(NPCDef, hook_npcdef_GetActions, i);
if(bytes > 0)then
begin
Result[c] := GetJavaString(bytes, 255);
inc(c);
end;
SmartFreeObject(bytes);
end;
SetLength(Result, c);
end;

{*******************************************************************************
Function SortNPCs(NPCs:array of TNPC):array of TNPC;
By: Widget edited by lordsaturn
Description: Sorts NPCs by distance from you.
*******************************************************************************}
function SortNPCs(NPCs:array of TNPC): TNPCArray;
var
i,i2, L: integer;
tpa: TPointArray;
begin
L := GetArrayLength(NPCs);
if L < 1 then Exit;
SetArrayLength(TPA, L);
SetArrayLength(Result, L);
for i := 0 to L-1 do
TPA[i] := NPCs[i].Tile;
SortTPAFrom(TPA, GetMyPos);
for i := 0 to L-1 do
for i2 := 0 to L-1 do
if (TPA[i].x=NPCs[i2].Tile.x) and (TPA[i].y=NPCs[i2].Tile.y) then
Result[i] := NPCs[i2];
end;

{*******************************************************************************
function GetNPCs(Null: Boolean): TNPCArray;
By: Drags111
Description: Stores all the loaded NPCs into an array of TNPC. If Null = True
then it will include Null NPCs.
*******************************************************************************}
function GetAllNPCs(Null: Boolean):array of TNPC;
var
i, c, NumNPCs, Index, TheNPC, TheNPCDef, TheBytes, TheNPCNode: integer;
begin
NumNPCs := SmartGetFieldInt(0,hook_static_NPCCount);
if (NumNPCs < 1) then Exit;
SetArrayLength(Result,NumNPCs);
for i := 0 to (NumNPCs-1) do
try
Index := SmartGetFieldArrayInt(0, hook_static_NPCIndexArray, i);
TheNPCNode := SmartGetFieldArrayObject(0, hook_static_NPCNodes, i);
TheNPC := SmartGetFieldObject(TheNPCNode, hook_npcnode_GetNPC);
TheNPCDef := SmartGetFieldObject(TheNPC, hook_npc_NPCDef);
TheBytes := SmartGetFieldObject(TheNPCDef, hook_npcdef_GetName);

if((not Null) and (lowercase(trim(GetJavaString(TheBytes, 255))) = 'null'))then
continue;
Result[c].Index := Index;
Result[c].ID := SmartGetFieldInt(TheNPCDef, hook_npcdef_GetID);
Result[c].Name := GetJavaString(TheBytes, 255);
Result[c].Actions := _GetNPCActionArray(TheNPCDef);
Result[c].Tile.X := (SmartGetFieldInt(0, hook_static_BaseX) + (SmartGetFieldInt(TheNPC, hook_animable_PixelX) / 512));
Result[c].Tile.Y := (SmartGetFieldInt(0, hook_static_BaseY) + (SmartGetFieldInt(TheNPC, hook_animable_PixelY) / 512));
Result[c].Pixel.X := SmartGetFieldInt(TheNPC, hook_animable_PixelX) mod 512;
Result[c].Pixel.Y := SmartGetFieldInt(TheNPC, hook_animable_PixelY) mod 512;
Result[c].Moving := (SmartGetFieldInt(TheNPC, hook_character_Motion)>0);
Result[c].Animation := SmartGetFieldInt(TheNPC, hook_character_Animation);
Result[c].Height := iabs(SmartGetFieldInt(TheNPC, hook_character_GetHeight));
Result[c].HPRatio := SmartGetFieldInt(TheNPC, hook_character_HPRatio) * 100 / $FF;
Result[c].Fighting := (SmartGetFieldInt(TheNPC, hook_character_LoopCycleStatus) >
SmartGetFieldInt(0, hook_static_LoopCycle));
Result[c].Orientation := Round(FixD(180 + (SmartGetFieldInt(TheNPC, hook_character_Orientation)* 45) / 2048));
Result[c].Level := SmartGetFieldInt(TheNPCDef, hook_npcdef_GetLevel);
Result[c].Interacting := SmartGetFieldInt(TheNPC, hook_character_GetInteracting);
Inc(c);

finally
SmartFreeObject(TheNPCNode);
SmartFreeObject(TheNPC);
SmartFreeObject(TheNPCDef);
SmartFreeObject(TheBytes);
end;
SetLength(Result, c);
end;

{*******************************************************************************
function GetNullNPCsByMulti(TheVarArr: TVariantArray):TNPCArray;
: Drags111/Naike/mormonman
Description: Returns the npc array by TheVarArr(IDs and names). Includes Null
npcs.
*******************************************************************************}
function GetNullNPCsMulti(TheVarArr: TVariantArray):TNPCArray;
var
vType, i, resCounter, Hi, Hig, h: Integer;
NPCs: TNPCArray;
b: boolean;
begin
NPCs := SortNPCs(GetAllNPCs(True));
SetLength(Result, Length(NPCs));
Hig := High(TheVarArr);
Hi := High(NPCs);
for i := 0 to Hi do
for h := 0 to Hig do
begin
vType := VarType(TheVarArr[h]);
if (vType = varString) then
TheVarArr[h] := LowerCase(Trim(TheVarArr[h]));
case vType of
varInteger: B := NPCs[i].ID = TheVarArr[h];
varString: B := (Pos(TheVarArr[h], LowerCase(Trim(NPCs[i].Name))) > 0);
else Exit;
end;
if not B then
Continue;
Result[resCounter] := NPCs[i];
inc(resCounter);
end;

SetLength(Result, resCounter);
end;

{*******************************************************************************
function GetNullNPCs(TheVar: Variant):TNPCArray;
By: Drags111/Naike/mormonman
Description: Returns the npc array by TheVar(ID or name). Includes Null npcs.
*******************************************************************************}
function GetNullNPCs(TheVar: Variant):TNPCArray;
begin
Result := GetNullNPCsMulti([TheVar]);
end;

{*******************************************************************************
function GetNullNPCMulti(TheVarArr: TVariantArray):TNPC;
By: Drags111/Naike/mormonman
Description: Returns the npc by TheVarArr(IDs or names). Includes Null npcs.
*******************************************************************************}
function GetNullNPCMulti(TheVarArr: TVariantArray):TNPC;
var
NPCs: TNPCArray;
begin
Result := NULL_NPC;
NPCs := GetNullNPCsMulti(TheVarArr);
if Length(NPCs) < 1 then Exit;
Result := NPCs[0];
end;

{*******************************************************************************
function GetNullNPC(TheVar: Variant):TNPC;
By: Drags111/Naike/mormonman
Description: Returns the npc by TheVar(ID or name). Includes Null npcs.
*******************************************************************************}
function GetNullNPC(TheVar: Variant):TNPC;
begin
Result := GetNullNPCMulti([TheVar]);
end;

{*******************************************************************************
function GetNPCsMulti(TheVarArr: TVariantArray): TNPCArray;
By: Widget, lordsaturn, Narcle, Nava2 and mormonman
Description: Returns all the currently loaded NPCs using TheVarArr, which will
take either strings or Integers. The String is a part of the NPC
name, and an Integer is the NPCType (ID).
*******************************************************************************}
function GetNPCsMulti(TheVarArr: TVariantArray): TNPCArray;
var
vType, i, resCounter, Hi, Hig, h: Integer;
NPCs: TNPCArray;
b: boolean;
begin
{
Initialize the result array, setup for looping.
}
NPCs := SortNPCs(GetAllNPCs(False));
SetLength(Result, Length(NPCs));
Hig := High(TheVarArr);
Hi := High(NPCs);
for i := 0 to Hi do
for h := 0 to Hig do
begin
vType := VarType(TheVarArr[h]);
if (vType = varString) then
TheVarArr[h] := LowerCase(Trim(TheVarArr[h]));
case vType of
varInteger: B := NPCs[i].ID = TheVarArr[h];
varString: B := (Pos(TheVarArr[h], LowerCase(Trim(NPCs[i].Name))) > 0);
else Exit;
end;
if not B then
Continue;
Result[resCounter] := NPCs[i];
inc(resCounter);
end;

SetLength(Result, resCounter);
end;

{*******************************************************************************
function GetNPCs(TheVar: Variant): TNPCArray;
By: Widget, lordsaturn, Narcle, Nava2 and mormonman
Description: Returns all the currently loaded NPCs using TheVar, which will
take either a string or an Integer. The String is a part of the NPC
name, and an Integer is the NPCType (ID).
*******************************************************************************}
function GetNPCs(TheVar: Variant): TNPCArray;
begin
Result := GetNPCsMulti([TheVar]);
end;

{*******************************************************************************
function GetNPCMulti(TheVarArr: TVariantArray):TNPC;
By: Drags111/mormonman
Description: Returns the npc by TheVarArr (names or IDs).
*******************************************************************************}
function GetNPCMulti(TheVarArr: TVariantArray):TNPC;
var
NPCs: TNPCArray;
begin
Result := NULL_NPC;
NPCs := GetNPCsMulti(TheVarArr);
if Length(NPCs) < 1 then Exit;
Result := NPCs[0];
end;

{*******************************************************************************
function GetNPC(TheVar: Variant):TNPC;
By: Drags111/mormonman
Description: Returns the npc by TheVar (name or ID).
*******************************************************************************}
function GetNPC(TheVar: Variant):TNPC;
begin
Result := GetNPCMulti([TheVar]);
end;

{*******************************************************************************
function GetNPCsAt(T: TTile): TNPCArray;
By:
Description: Returns an array of the NPCs at the given tile
*******************************************************************************}
function GetNPCsAt(T: TTile): TNPCArray;
var
i, h, c: Integer;
Index, TheNPCNode, TheNPC, TheNPCDef, TheBytes: Integer;
tmp_tile : TTile;
begin
h := SmartGetFieldInt(0, hook_static_NPCCount);
SetLength(Result, h);
Dec(h);
for i := 0 to h do
try
Index := SmartGetFieldArrayInt(0, hook_static_NPCIndexArray, i);
TheNPCNode := SmartGetFieldArrayObject(0, hook_static_NPCNodes, i);
TheNPC := SmartGetFieldObject(TheNPCNode, hook_npcnode_GetNPC);
tmp_tile := Tile(
SmartGetFieldInt(0,hook_static_BaseX) +
SmartGetFieldInt(TheNPC, hook_animable_PixelX) / 512,
SmartGetFieldInt(0,hook_static_BaseY) +
SmartGetFieldInt(TheNPC, hook_animable_PixelY) / 512);

if (tmp_tile = t) then
begin
TheNPCDef := SmartGetFieldObject(TheNPC, hook_npc_NPCDef);
TheBytes := SmartGetFieldObject(TheNPCDef, hook_npcdef_GetName);
Result[c].Index := Index;
Result[c].ID := SmartGetFieldInt(TheNPCDef, hook_npcdef_GetID);
Result[c].Name := GetJavaString(TheBytes, 255);
Result[c].Actions := _GetNPCActionArray(TheNPCDef);
Result[c].Tile.X := (SmartGetFieldInt(0, hook_static_BaseX) + (SmartGetFieldInt(TheNPC, hook_animable_PixelX) / 512));
Result[c].Tile.Y := (SmartGetFieldInt(0, hook_static_BaseY) + (SmartGetFieldInt(TheNPC, hook_animable_PixelY) / 512));
Result[c].Moving := (SmartGetFieldInt(TheNPC, hook_character_Motion)>0);
Result[c].Animation := SmartGetFieldInt(TheNPC, hook_character_Animation);
Result[c].Height := iabs(SmartGetFieldInt(TheNPC, hook_character_GetHeight));
Result[c].HPRatio := SmartGetFieldInt(TheNPC, hook_character_HPRatio) * 100 / $FF;
Result[c].Fighting := (SmartGetFieldInt(TheNPC, hook_character_LoopCycleStatus) >
SmartGetFieldInt(0, hook_static_LoopCycle));
Result[c].Orientation := Round(FixD(180 + (SmartGetFieldInt(TheNPC, hook_character_Orientation)* 45) / 2048));
Result[c].Level := SmartGetFieldInt(TheNPCDef, hook_npcdef_GetLevel);
Result[c].Interacting := SmartGetFieldInt(TheNPC, hook_character_GetInteracting);
Inc(c);
end;
finally
SmartFreeObject(TheNPCNode);
SmartFreeObject(TheNPC);
end;
SetLength(Result, c);
end;

{*******************************************************************************
function FindNPCsMulti(TheVarArr: Variant; var NPCs: TNPCArray): Boolean;
By: lordsaturn/mormonman
Description: If any NPC is found according to TheVarArr, the NPCs are placed in
the NPCs array. Results true if found; false otherwise.
*******************************************************************************}
function FindNPCsMulti(TheVarArr: Variant; var NPCs: TNPCArray): Boolean;
begin
NPCs := GetNPCsMulti(TheVarArr);
if Length(NPCs) < 1 then Exit;
Result := NPCs[0].ID > -1;
end;

{*******************************************************************************
function FindNPCs(TheVar: Variant; var NPCs: TNPCArray): Boolean;
By: lordsaturn/mormonman
Description: If the NPC is found according to TheVar, the NPC is placed in the
NPCs array. Results true if found; false otherwise.
*******************************************************************************}
function FindNPCs(TheVar: Variant; var NPCs: TNPCArray): Boolean;
begin
Result := FindNPCsMulti([TheVar], NPCs);
end;

{*******************************************************************************
function FindNPCMulti(TheVarArr: Variant; var NPC: TNPC): Boolean;
By: lordsaturn/mormonman
Description: If the NPC is found according to TheVarArr, the NPC is placed in
the NPC variable. Results true if found; false otherwise.
*******************************************************************************}
function FindNPCMulti(TheVarArr: Variant; var NPC: TNPC): Boolean;
begin
NPC := GetNPCMulti(TheVarArr);
Result := NPC.ID > -1;
end;

{*******************************************************************************
function FindNPC(TheVar: Variant; var NPC: TNPC): Boolean;
By: lordsaturn/mormonman
Description: If the NPC is found according to TheVar, the NPC is placed in the
NPC variable. Results true if found; false otherwise.
*******************************************************************************}
function FindNPC(TheVar: Variant; var NPC: TNPC): Boolean;
begin
Result := FindNPCMulti([TheVar], NPC);
end;

{*******************************************************************************
function ValidNullNPCMulti(TheVarArr: TVariantArray): Boolean;
By: Drags111/Naike/mormonman
Description: Returns true if npc designated by TheVarArr(names or IDs) is found.
*******************************************************************************}
function ValidNullNPCMulti(TheVarArr: TVariantArray): Boolean;
var
vType, i, Hi, Hig, h: Integer;
NPCs: TNPCArray;
begin
NPCs := SortNPCS(GetAllNPCs(True));
Hi := High(NPCs);
Hig := High(TheVarArr);
for i := 0 to Hi do
for h := 0 to Hig do
begin
vType := VarType(TheVarArr[h]);
if (vType = varString) then
TheVarArr[h] := LowerCase(Trim(TheVarArr[h]));
case vType of
varInteger: Result := NPCs[i].ID = TheVarArr[h];
varString: Result := (Pos(TheVarArr[h], LowerCase(Trim(NPCs[i].Name))) > 0);
else Exit;
end;
if Result then Exit;
end;
end;

{*******************************************************************************
function ValidNullNPC(ID: Integer): Boolean;
By: Drags111/Naike/mormonman
Description: Returns true if npc designated by TheVar(name or ID) is found.
*******************************************************************************}
function ValidNullNPC(TheVar: Variant): Boolean;
begin
Result := ValidNullNPCMulti([TheVar]);
end;

{*******************************************************************************
function ValidNPC(TheVar: Variant): Boolean;
By: lordsaturn
Description: Results true if the npc is found
*******************************************************************************}
function ValidNPC(TheVar: Variant): Boolean;
var
NPC: TNPC;
begin
Result := FindNPC(TheVar, NPC);
end;

{*******************************************************************************
procedure DumpNPCs(NPCs: TNPCArray);
By: Drags111
Description: Prints out the array of NPCs. Mainly for debugging purposes.
*******************************************************************************}
procedure DumpNPCs(NPCs: TNPCArray);
var
i, Hi: integer;
begin
Hi := High(NPCs);
for i := 0 to Hi do
begin
Writeln('NPC: '+NPCs[i].Name);
Writeln(' '+'Index: '+ ToStr(NPCs[i].Index));
Writeln(' '+'ID: '+ToStr(NPCs[i].ID));
Writeln(' '+'Actions: '+ ToStr(NPCs[i].Actions));
Writeln(' '+'Tile: '+ ToStr(NPCs[i].Tile));
Writeln(' '+'Animation: '+ ToStr(NPCs[i].Animation));
Writeln(' '+'Height: '+ ToStr(NPCs[i].Height));
Writeln(' '+'Fighting: '+ ToStr(NPCs[i].Fighting));
Writeln(' '+'IsMoving: '+ ToStr(NPCs[i].Moving));
Writeln(' '+'HPRatio: '+ ToStr(NPCs[i].HPRatio));
Writeln(' '+'Level: '+ ToStr(NPCs[i].Level));
Writeln(' '+'Orientation: '+ ToStr(NPCs[i].Orientation));
Writeln(' '+'Interacting: '+ ToStr(NPCs[i].Interacting));
end;
end;

i luffs yeww

2010-12-30 18:39:43

Does it work? Compile? etc.? Then yes.

mormonman

2010-12-30 19:16:33

From: i luffs yeww
Does it work? Compile? etc.? Then yes.


Yes. But people will have to change scripts.

pyroryan

2010-12-30 20:49:10

I like the result of your reorganizing, but it would break scripts, which is bound to happen. A smooth transition is preferential but I don't see how it could be smooth. Any ideas?

mormonman

2010-12-30 21:10:13

It's not just reorganization, it fixes the sorting issues with GetNPC because the old stuff had Hi downto 0. I also added functions for multi variant searching which has been needed for a while now.

Bad Boy JH

2011-01-01 05:52:08

Could we have FindNPCEx and FindNPC, keeping FindNPC as how it was before, using FindNPCEx, which gets both Null and Non-Null NPCs

mormonman

2011-01-05 15:40:15

No other opinions on this? Commit then?

pyroryan

2011-01-05 21:20:30

I was actually wondering what other devs were thinking since this will break some scripts.
If it were just me and I didn't have to deal with broken scripts, then I'd fully support this change since it reduces the amount of redundant code.

lordsaturn

2011-01-06 05:20:49

Let's wait until SRL 5 until we commit this, when everyone has to rewrite scripts anyways.

Bonfield

2011-01-06 05:22:47

any idea on the timeframe for SRL 5? it has been talked about for some time now?

also how drastic are these changes?

EDIT: kinda sounds like im being a bit of a dick, my bad

Wizzup?

2011-01-06 11:29:12

Changes aren't too drastic. SRL 5 has seen a lot of work but atm the development died a bit again. People are talking too much and coding nothing.

Naike

2011-01-06 13:25:42

I'm not going to commit anything breaking every single script using NPCs.simba

The change is indeed very neat, but it'll have to wait until we're forced to update all scripts!

mormonman

2011-01-06 13:49:40

From: Naike
I'm not going to commit anything breaking every single script using NPCs.simba

The change is indeed very neat, but it'll have to wait until we're forced to update all scripts!


If you went through it you would know that it isn't just "neat" it fixes all the problems people had with finding the closest npc and why they always used their own methods to sort through npcs. IMO it is a required update.

pyroryan

2011-01-06 14:30:50

Give mormonman commit rights. Then hope all the complainers complain to him :). Seems like a good compromise to me.

3Garrett3

2011-01-06 16:26:02

From: Bad Boy JH
Could we have FindNPCEx and FindNPC, keeping FindNPC as how it was before, using FindNPCEx, which gets both Null and Non-Null NPCs


Do this.

mormonman

2011-01-06 17:12:55

Would you like all the "Null" names to be changed to "Ex" functions?

Naike

2011-01-06 17:25:23

From: mormonman
If you went through it you would know that it isn't just "neat" it fixes all the problems people had with finding the closest npc and why they always used their own methods to sort through npcs. IMO it is a required update.



Wait until We can update without breaking every single script.. Be patient.

Edit: nice work btw :)

Edit2(Back from iPod): It's indeed a needed update, but when everything is working smooth it's no point to add something breaking pretty much everything.

Sir R. M8gic1an

2011-01-07 10:25:14

What's a null npc? / Why would we want to get their info?

~RM

mormonman

2011-01-07 11:31:45

From: Sir R. Magician
What's a null npc? / Why would we want to get their info?

~RM


One that has a 'null' value for the npcdef_getName.

3Garrett3

2011-01-07 11:32:36

From: Sir R. Magician
What's a null npc? / Why would we want to get their info?

~RM


IIRC a null npc is simply a blank npc that Jagex has incorporated. We can't actually see them, but if you do a dump of the NPCs on your screen, sometimes you will see an NPC with NULL as all of the (the word escapes me right now, attributes?) for it.

I don't know why you'd want to find them, it has no point in gameplay.

mormonman

2011-01-07 11:40:03

From: 3Garrett3
IIRC a null npc is simply a blank npc that Jagex has incorporated. We can't actually see them, but if you do a dump of the NPCs on your screen, sometimes you will see an NPC with NULL as all of the (the word escapes me right now, attributes?) for it.

I don't know why you'd want to find them, it has no point in gameplay.


Randoms use them.

Edit: Committed and locked.