polserver/testsuite/pol/testpkgs/npc/test_npc.src
turleypol d873551c25
removed pol_distance/inrange* functions (#556)
* removed pol_distance/inrange* functions
replaced lastxyz with Pos4d

* replaced WorldIterator::InVisualRange with InMaxVisualRange returning
all objects in maximum update range. Adapted each caller, they now have
to check in_visual_range
Multis should now be send to clients with its footprint in mind.
added testscript for boat moving in/out of range

* removed non pos InRange/InBox functions
gamestate.update_range doesnt need to be a Vector, renamed

* corrected send_action_to_inrange

* replaced clip methods with general numeric type clamp function

* added Range2d constructor with radius

* splitted update_range. chr has now a los_size (how far can it see) and
an object has a visible_size (0 for objects 1/2 footprint for multis)

* use in_range instead of pol_distance

* corrected order of checks

* fixed warnings

* fixed visual size of multis
testclient added wornitems pkt support
added tests for los

* corechanges
2023-12-25 22:02:52 +01:00

263 lines
8.5 KiB
Text

use uo;
use os;
use vitals;
include "testutil";
program npc_ai()
return 1;
endprogram
exported function npc_ai_movement()
var npc:=CreateNPCFromTemplate(":testnpc:test_movement",100,100,0);
if (!npc)
return ret_error("Could not create NPC: "+npc);
endif
while(1)
sleepms(10);
if (!npc.process)
if (!npc)
break;
endif
return ret_error(npc.getprop("testerror"));
endif
endwhile
return 1;
endfunction
function wait_for_prop(npc, propname, max_try := 50)
while(npc and max_try > 0)
sleepms(10);
max_try--;
var prop := npc.getprop(propname);
if (prop.errortext == "Property not found")
continue;
endif
return prop;
endwhile
return ret_error("Timeout waiting for {} on serial {}".format(propname, npc.serial));
endfunction
exported function npc_enteredarea()
return npc_test_areaevents(":testnpc:test_enteredarea", 1);
endfunction
exported function npc_enteredarea_npconly()
return npc_test_areaevents(":testnpc:test_enteredarea_onlynpc", 1);
endfunction
exported function npc_enteredarea_pconly()
return npc_test_areaevents(":testnpc:test_enteredarea_onlypc", 0);
endfunction
function npc_test_areaevents(template, expected_to_see)
var x := 100;
var y := 100;
var range := 10; // defined in ai_enteredarea.src
var npc := CreateNPCFromTemplate(template,x,y,0);
if (!npc)
return ret_error("Could not create NPC: "+npc);
endif
var ready := wait_for_prop(npc, "ready");
if (ready.errortext)
return ready;
endif
// test if it can see npcs created at the four borders of the event range
var probe_npc1 := CreateNPCFromTemplate(":testnpc:probe_npc",x+range,y+range,0);
var probe_npc2 := CreateNPCFromTemplate(":testnpc:probe_npc",x-range,y-range,0);
var probe_npc3 := CreateNPCFromTemplate(":testnpc:probe_npc",x-range,y+range,0);
var probe_npc4 := CreateNPCFromTemplate(":testnpc:probe_npc",x+range,y-range,0);
// test if it CANT see npcs created right outside the border of the event range
var probe_npc1_notseen := CreateNPCFromTemplate(":testnpc:probe_npc",x+range,y+range+1,0);
var probe_npc2_notseen := CreateNPCFromTemplate(":testnpc:probe_npc",x-range,y-range-1,0);
var probe_npc3_notseen := CreateNPCFromTemplate(":testnpc:probe_npc",x-range-1,y+range,0);
var probe_npc4_notseen := CreateNPCFromTemplate(":testnpc:probe_npc",x+range+1,y-range,0);
// test if it can see an npc created outside, then moved in
var probe_npc_outside_then_in := CreateNPCFromTemplate(":testnpc:probe_npc",x+range+10,y-range-10,0);
MoveObjectToLocation(probe_npc_outside_then_in, x+range-2, y+range-2, 0);
// the order matters
var in_range_npcs := {
probe_npc1.serial,
probe_npc2.serial,
probe_npc3.serial,
probe_npc4.serial,
probe_npc_outside_then_in.serial
};
var nExpected := in_range_npcs.size();
if (!expected_to_see)
var who_entered := wait_for_prop(npc, "who_entered", max_try := 3);
if (who_entered.errortext)
if (who_entered.errortext["Timeout waiting for"])
//expected - go on
else
return who_entered;
endif
elseif (who_entered)
return ret_error("NPC saw other NPCs entering but shouldnt");
else
return ret_error("NPC did something odd: " + CStr(who_entered));
endif
else
var who_entered := wait_for_prop(npc, "who_entered");
if (who_entered.errortext)
return who_entered;
endif
if (who_entered.size() < nExpected)
return ret_error("NPC only received {} ENTEREDAREA events out of {}.".format(who_entered.size(), nExpected));
endif
foreach serial in who_entered
var idx := serial in in_range_npcs;
if (!idx)
return ret_error("Unexpected NPC was seen entering: {}".format(serial));
endif
if (_serial_iter != idx)
return ret_error("NPC seen entering out of order: {} / {}".format(idx, _serial_iter));
endif
endforeach
endif
// test if it can see them leaving
MoveObjectToLocation(probe_npc1, x+range+1, y+range+1, 0);
MoveObjectToLocation(probe_npc2, x-range-1, y-range-1, 0);
MoveObjectToLocation(probe_npc3, x-range-1, y+range+1, 0);
MoveObjectToLocation(probe_npc4, x+range+1, y-range-1, 0);
// this one too
MoveObjectToLocation(probe_npc_outside_then_in, x+range+20, y+range+20, 0);
// test that it DOESNT see them leaving
MoveObjectToLocation(probe_npc1_notseen, x+range+10, y+range+10, 0);
MoveObjectToLocation(probe_npc2_notseen, x-range-10, y-range-10, 0);
MoveObjectToLocation(probe_npc3_notseen, x-range-10, y+range+10, 0);
MoveObjectToLocation(probe_npc4_notseen, x+range+10, y-range-10, 0);
if (!expected_to_see)
var who_left := wait_for_prop(npc, "who_left", max_try := 3);
if (who_left.errortext)
if (who_left.errortext["Timeout waiting for"])
//expected - go on
else
return who_left;
endif
elseif (who_left)
return ret_error("NPC saw other NPCs leaving but shouldnt");
else
return ret_error("NPC did something odd: " + CStr(who_left));
endif
else
var who_left := wait_for_prop(npc, "who_left");
if (who_left.errortext)
return who_left;
endif
if (who_left.size() < nExpected)
return ret_error("NPC only received {} LEFTAREA events out of {}.".format(who_left.size(), nExpected));
endif
foreach serial in who_left
var idx := serial in in_range_npcs;
if (!idx)
return ret_error("Unexpected NPC was seen leaving: {}".format(serial));
endif
if (_serial_iter != idx)
return ret_error("NPC seen leaving out of order: {} / {}".format(idx, _serial_iter));
endif
endforeach
endif
npc.kill();
probe_npc1.kill();
probe_npc2.kill();
probe_npc3.kill();
probe_npc4.kill();
probe_npc1_notseen.kill();
probe_npc2_notseen.kill();
probe_npc3_notseen.kill();
probe_npc4_notseen.kill();
probe_npc_outside_then_in.kill();
return 1;
endfunction
exported function test_load_desc_props()
var npc:=CreateNPCFromTemplate(":testnpc:load_npc",100,100,0);
if (!npc)
return ret_error("Could not create NPC: "+npc);
endif
if (!npc.weapon.getprop("weaponcprop"))
npc.kill();
return ret_error("Failed to load weapon cprop");
endif
if (!npc.shield.getprop("shieldcprop"))
npc.kill();
return ret_error("Failed to load shield cprop");
endif
if (!npc.no_drop_exception)
npc.kill();
return ret_error("Failed to load nodropexception");
endif
npc.kill();
return 1;
endfunction
exported function test_npc_realm_move()
// crashed by wrongly converting coordinates between realms
var npc:=CreateNPCFromTemplate(":testnpc:load_npc",100,100,0);
if (!npc)
return ret_error("Could not create NPC: "+npc);
endif
MoveObjectToLocation(npc,1000,1000,0,"britannia2",MOVEOBJECT_FORCELOCATION);
if (npc.x != 1000 || npc.y != 1000 || npc.realm != "britannia2")
var res:=$"Failed initial move: {npc.x},{npc.y},{npc.realm}";
npc.kill();
return ret_error(res);
endif
MoveObjectToLocation(npc,10,10,0,"britannia",MOVEOBJECT_FORCELOCATION);
if (npc.x != 10 || npc.y != 10 || npc.realm != "britannia")
var res:=$"Failed to move: {npc.x},{npc.y},{npc.realm}";
npc.kill();
return ret_error(res);
endif
npc.kill();
return 1;
endfunction
/*
Test that with WarmodeInhibitsRegen=3 (NPCs Only), an _NPC_ in war mode _will not_ regenerate health.
*/
exported function npc_warmodeinhibitsregen()
var npc:=CreateNPCFromTemplate(":testnpc:load_npc",100,100,0);
if (!npc)
return ret_error("Could not create NPC: "+npc);
endif
npc.setwarmode(1);
SetVital( npc, "Life", GetVital( npc, "Life" ) / 2);
var damaged_health := GetVital( npc, "Life" );
Sleep(6);
var waited_health := GetVital( npc, "Life" );
npc.kill();
if (damaged_health != waited_health)
return ret_error($"NPC health changed between sleeping: {damaged_health} -> {waited_health}");
endif
return 1;
endfunction