mirror of
https://github.com/polserver/polserver
synced 2026-08-13 08:23:08 -04:00
167 lines
4.4 KiB
Text
167 lines
4.4 KiB
Text
use uo;
|
|
use os;
|
|
|
|
include "testutil";
|
|
include "sysevent";
|
|
|
|
var npc1, npc2;
|
|
|
|
program npc_ai()
|
|
npc1 := CreateNPCFromTemplate( ":testattack:test_attack", 100, 100, 0 );
|
|
|
|
if ( !npc1 )
|
|
return ret_error( "Could not create NPC: " + npc1 );
|
|
endif
|
|
|
|
npc1.hitchance_mod := 1000;
|
|
SetObjProperty( npc1, "#TestPid", GetPid() );
|
|
SetName( npc1, "npc1" );
|
|
npc1.hidden := 1;
|
|
|
|
npc2 := CreateNPCFromTemplate( ":testattack:test_attack", 101, 101, 0 );
|
|
|
|
if ( !npc2 )
|
|
return ret_error( "Could not create NPC: " + npc2 );
|
|
endif
|
|
|
|
npc2.hitchance_mod := 1000;
|
|
SetObjProperty( npc2, "#TestPid", GetPid() );
|
|
SetName( npc2, "npc2" );
|
|
|
|
return 1;
|
|
endprogram
|
|
|
|
// Tests that when an attacker unhides, it will attack opponent.
|
|
// `npc1` hides, attacks `npc2`, waits 2 seconds, then unhides. Check that both
|
|
// NPCs attack each other at game clock time `t`, where `t` is the clock time where
|
|
// the NPC unhides.
|
|
exported function attack_on_unhide_attacker()
|
|
var err, evs, t;
|
|
|
|
reset_npcs();
|
|
|
|
// Hide npc1
|
|
npc1.hidden := 1;
|
|
|
|
// Send an event to npc1 to attack npc2 + unhide.
|
|
npc1.process.sendevent( struct{ type := SYSEVENT_ENGAGED, source := npc2, sleep := 2, unhide := true } );
|
|
|
|
var initial_evs := collect_events( 1, "No event for NPC BEFORE_UNHIDE" );
|
|
if ( !initial_evs )
|
|
return initial_evs;
|
|
elseif ( initial_evs[1].type != "BEFORE_UNHIDE" )
|
|
return ret_error( "Unexpected first event type: expected 'BEFORE_UNHIDE', actual '{initial_evs[1].type}'" );
|
|
endif
|
|
|
|
// Collect two attack events
|
|
if (!(evs := collect_events( 2 )))
|
|
return evs;
|
|
endif
|
|
|
|
// The attack should happen when npc1 unhid.
|
|
t := initial_evs[1].gameclock;
|
|
|
|
if (!validate_events(err, evs, t))
|
|
return err;
|
|
endif
|
|
|
|
// NPC and corpse cleanup handled in cleanup.src
|
|
|
|
return 1;
|
|
endfunction
|
|
|
|
// Tests that when an defender unhides, its attacker will still attack.
|
|
// `npc1` attacks `npc2`, `npc2` hides and clears opponent, waits 2 seconds, then unhides.
|
|
// Check that both NPCs attack each other (since `npc2` did NOT clear opponent) at game
|
|
// clock time `t`, where `t` is the clock time where the NPC unhides.
|
|
exported function attack_on_unhide_defender()
|
|
var err, evs, t;
|
|
|
|
reset_npcs();
|
|
|
|
// npc1 attacks npc2
|
|
npc1.process.sendevent( struct{ type := SYSEVENT_ENGAGED, source := npc2, sleep := 0, unhide := false } );
|
|
|
|
// Collect two attack events
|
|
if (!(evs := collect_events( 2 )))
|
|
return evs;
|
|
endif
|
|
|
|
// Both attacks should happen at the same time
|
|
t := evs[1].gameclock;
|
|
|
|
if (!validate_events(err, evs, t))
|
|
return err;
|
|
endif
|
|
|
|
// Hide npc2, clear its opponent, and sleep to reset npc1's swing timer.
|
|
npc2.hidden := 1;
|
|
npc2.process.sendevent( struct{ type := SYSEVENT_DISENGAGED } );
|
|
Sleep(2);
|
|
|
|
// Unhide npc2. Since npc1 is still attacking, both should get a hit.
|
|
npc2.hidden := 0;
|
|
|
|
// Both attacks should happen at the same time, when npc2 unhid.
|
|
t := ReadGameClock();
|
|
|
|
// Collect two attack events
|
|
if (!(evs := collect_events( 2 )))
|
|
return evs;
|
|
endif
|
|
|
|
if (!validate_events(err, evs, t))
|
|
return err;
|
|
endif
|
|
|
|
// NPC and corpse cleanup handled in cleanup.src
|
|
|
|
return 1;
|
|
endfunction
|
|
|
|
|
|
/**
|
|
* Helper functions
|
|
*/
|
|
|
|
// Send event to both npcs to clear opponent.
|
|
function reset_npcs()
|
|
npc1.process.sendevent( struct{ type := SYSEVENT_DISENGAGED } );
|
|
npc2.process.sendevent( struct{ type := SYSEVENT_DISENGAGED } );
|
|
clear_event_queue();
|
|
endfunction
|
|
|
|
// Ensure gameclock and attacker-defender sequence of two events.
|
|
function validate_events(byref err, byref evs, t)
|
|
var failure :=
|
|
( evs[1].gameclock != t ) || // First hit did not happen on unhide.
|
|
( evs[2].gameclock != t ) || // Second hit did not happen on unhide.
|
|
( evs[1].attacker != evs[2].defender ) || // First hit attacker is not second hit defender
|
|
( evs[1].defender != evs[2].attacker ); // First hit defender is not second hit attacker
|
|
|
|
if ( failure )
|
|
return err := ret_error( $"Unexpected attacker-defender sequence. Expected both hits at gameclock {t}, attacker[1] == defender[2], defender[1] == attacker[2].\n\nEvents: {PackJSON(evs, true)}" );
|
|
endif
|
|
|
|
return 1;
|
|
endfunction
|
|
|
|
// Collect a number of events
|
|
function collect_events( count, errorMessage := "No event from NPC script received." )
|
|
var evs := array{};
|
|
|
|
while ( true )
|
|
var ev := wait_for_event( 5 );
|
|
if ( ev )
|
|
evs.append( ev );
|
|
if ( evs.size() >= count )
|
|
break;
|
|
endif
|
|
continue;
|
|
endif
|
|
|
|
return ret_error( errorMessage );
|
|
endwhile
|
|
|
|
return evs;
|
|
endfunction
|