forked from Mirrors/openclonk
Test for #1974
The test cannot reproduce the bug at the moment, so consider it a prototype.install-platforms
parent
5944146f2b
commit
88aac09064
|
@ -0,0 +1,5 @@
|
|||
[Head]
|
||||
Title=Clonk Attachments
|
||||
|
||||
[Landscape]
|
||||
NoScan=1
|
|
@ -0,0 +1,371 @@
|
|||
/**
|
||||
Clonk Attachments
|
||||
|
||||
Unit tests for displaying wearables and tools on the Clonk,
|
||||
related to bug #1974 - this is not in the issues folder, though,
|
||||
because the test logic is a lot different - namely you cannot
|
||||
do everything in one function call for most tests.
|
||||
|
||||
Invokes tests by calling the global function Test*_OnStart(int plr)
|
||||
and iterate through all tests.
|
||||
The test is completed once Test*_Completed() returns true.
|
||||
Then Test*_OnFinished() is called, to be able to reset
|
||||
the scenario for the next test.
|
||||
|
||||
With LaunchTest(int nr) a specific test can be launched when
|
||||
called during runtime. A test can be skipped by calling the
|
||||
function SkipTest().
|
||||
|
||||
@author Maikel (test logic), Marky (actual tests)
|
||||
*/
|
||||
|
||||
static const HLINE = "=====================================";
|
||||
|
||||
static script_plr, test;
|
||||
|
||||
protected func Initialize()
|
||||
{
|
||||
// Add the no power rule, this is about liquids.
|
||||
CreateObject(Rule_NoPowerNeed);
|
||||
// Create a script player for some tests.
|
||||
script_plr = nil;
|
||||
CreateScriptPlayer("Buddy", RGB(0, 0, 255), nil, CSPF_NoEliminationCheck);
|
||||
return;
|
||||
}
|
||||
|
||||
protected func InitializePlayer(int plr)
|
||||
{
|
||||
// Set zoom to full map size.
|
||||
SetPlayerZoomByViewRange(plr, LandscapeWidth(), nil, PLRZOOM_Direct);
|
||||
|
||||
// No FoW to see everything happening.
|
||||
SetFoW(false, plr);
|
||||
|
||||
// All players belong to the first team.
|
||||
// The second team only exists for testing.
|
||||
SetPlayerTeam(plr, 1);
|
||||
|
||||
// Initialize script player.
|
||||
if (GetPlayerType(plr) == C4PT_Script)
|
||||
{
|
||||
// Store the player number.
|
||||
if (script_plr == nil)
|
||||
script_plr = plr;
|
||||
// No crew needed.
|
||||
GetCrew(plr)->RemoveObject();
|
||||
return;
|
||||
}
|
||||
|
||||
// Move player to the start of the scenario.
|
||||
GetCrew(plr)->SetPosition(120, 150);
|
||||
|
||||
// Some knowledge to construct a flagpole.
|
||||
GetCrew(plr)->CreateContents(Hammer);
|
||||
SetPlrKnowledge(plr, Flagpole);
|
||||
|
||||
// Add test control effect.
|
||||
test = CreateEffect(IntTestControl, 100, 2);
|
||||
test.testnr = 1;
|
||||
test.launched = false;
|
||||
test.plr = plr;
|
||||
return;
|
||||
}
|
||||
|
||||
protected func RemovePlayer(int plr)
|
||||
{
|
||||
// Remove script player.
|
||||
if (GetPlayerType(plr) == C4PT_Script)
|
||||
{
|
||||
if (plr == script_plr)
|
||||
script_plr = nil;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*-- Test Control --*/
|
||||
|
||||
// Aborts the current test and launches the specified test instead.
|
||||
global func LaunchTest(int nr)
|
||||
{
|
||||
// Get the control effect.
|
||||
if (!test)
|
||||
{
|
||||
// Create a new control effect and launch the test.
|
||||
test = CreateEffect(IntTestControl, 100, 2);
|
||||
test.testnr = nr;
|
||||
test.launched = false;
|
||||
test.plr = GetPlayerByIndex(0, C4PT_User);
|
||||
return;
|
||||
}
|
||||
// Finish the currently running test.
|
||||
Call(Format("~Test%d_OnFinished", test.testnr));
|
||||
// Start the requested test by just setting the test number and setting
|
||||
// test.launched to false, effect will handle the rest.
|
||||
test.testnr = nr;
|
||||
test.launched = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Calling this function skips the current test, does not work if last test has been ran already.
|
||||
global func SkipTest()
|
||||
{
|
||||
if (!test)
|
||||
return;
|
||||
// Finish the previous test.
|
||||
Call(Format("~Test%d_OnFinished", test.testnr));
|
||||
// Start the next test by just increasing the test number and setting
|
||||
// test.launched to false, effect will handle the rest.
|
||||
test.testnr++;
|
||||
test.launched = false;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*-- Test Effect --*/
|
||||
|
||||
|
||||
static const IntTestControl = new Effect
|
||||
{
|
||||
Timer = func ()
|
||||
{
|
||||
// Launch new test if needed.
|
||||
if (!this.launched)
|
||||
{
|
||||
// Log test start.
|
||||
Log(HLINE);
|
||||
Log("Test %d started:", this.testnr);
|
||||
// Start the test if available, otherwise finish test sequence.
|
||||
if (!Call(Format("~Test%d_OnStart", this.testnr), this.plr))
|
||||
{
|
||||
Log("Test %d not available, the previous test was the last test.", this.testnr);
|
||||
Log(HLINE);
|
||||
Log("All tests have been successfully completed!");
|
||||
return FX_Execute_Kill;
|
||||
}
|
||||
this.launched = true;
|
||||
}
|
||||
// Check whether the current test has been finished.
|
||||
if (Call(Format("Test%d_Completed", this.testnr)))
|
||||
{
|
||||
this.launched = false;
|
||||
//RemoveTest();
|
||||
// Call the test on finished function.
|
||||
Call(Format("~Test%d_OnFinished", this.testnr));
|
||||
// Log result and increase test number.
|
||||
Log("Test %d successfully completed.", this.testnr);
|
||||
this.testnr++;
|
||||
}
|
||||
return FX_OK;
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
global func IsWaiting()
|
||||
{
|
||||
if (test)
|
||||
{
|
||||
var wait = test.wait > 0;
|
||||
test.wait -= 1;
|
||||
return wait;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
global func Wait(int amount)
|
||||
{
|
||||
test.wait = Max(0, amount);
|
||||
}
|
||||
|
||||
/*-- Liquid Tests --*/
|
||||
|
||||
global func Test1_OnStart(int plr)
|
||||
{
|
||||
Log("Tools carried visibly on the Clonk when dying should be visible when picked up again");
|
||||
|
||||
if (test == nil)
|
||||
{
|
||||
Log("No test context");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get all definitions that are collectible
|
||||
test.test1_collectible_defs = [];
|
||||
for (var i = 0, def; def = GetDefinition(i); ++i)
|
||||
{
|
||||
if (def.Collectible // Only collectible items
|
||||
&& def.GetCarryMode) // Only things that can be displayed on the Clonk -> so, rocks, etc. are sorted out for now
|
||||
{
|
||||
PushBack(test.test1_collectible_defs, def);
|
||||
}
|
||||
}
|
||||
|
||||
// init data
|
||||
test.test1_length = GetLength(test.test1_collectible_defs);
|
||||
test.test1_index = 0;
|
||||
test.test1_item = [];
|
||||
test.test1_corpse = [];
|
||||
test.test1_corpse_display = [];
|
||||
test.test1_collector = [];
|
||||
test.test1_collector_display = [];
|
||||
test.test1_started = [];
|
||||
test.test1_finished = [];
|
||||
test.test1_passed = [];
|
||||
test.test1_comment = [];
|
||||
test.test1_store = CreateObject(Dummy);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
global func Test1_Completed()
|
||||
{
|
||||
GetCursor(test.plr)->Message("Test %d / %d", test.test1_index + 1, test.test1_length);
|
||||
|
||||
if (IsWaiting()) return false;
|
||||
|
||||
if (test.test1_index >= test.test1_length)
|
||||
{
|
||||
Log("Tested all collectible definitions with display, exiting now");
|
||||
return Test1_EvaluateResult();
|
||||
}
|
||||
Test1_Run();
|
||||
return false;
|
||||
}
|
||||
|
||||
global func Test1_OnFinished()
|
||||
{
|
||||
if (test.test1_store)
|
||||
{
|
||||
test.test1_store->RemoveObject();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
global func Test1_Run()
|
||||
{
|
||||
var cursor = GetCursor(test.plr);
|
||||
var index = test.test1_index;
|
||||
var corpse = test.test1_corpse[index];
|
||||
var item = test.test1_item[index];
|
||||
var collector = test.test1_collector[index];
|
||||
|
||||
// Already done?
|
||||
if (test.test1_finished[index])
|
||||
{
|
||||
if (corpse) corpse.Visibility = VIS_None;
|
||||
if (collector) collector.Visibility = VIS_None;
|
||||
if (item) item->Enter(test.test1_store);
|
||||
RemoveAll(Find_ID(Rock));
|
||||
test.test1_index += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Create an item
|
||||
if (!item || !test.test1_started[index])
|
||||
{
|
||||
test.test1_item[index] = item = CreateObject(test.test1_collectible_defs[index], 0, 0, script_plr);
|
||||
test.test1_started[index] = true;
|
||||
}
|
||||
|
||||
var collect_delay = 10;
|
||||
if (item->~IsCarryHeavy()) collect_delay += 30;
|
||||
|
||||
// Create someone to collect it later
|
||||
if (!collector)
|
||||
{
|
||||
test.test1_collector[index] = collector = CreateObject(Clonk, cursor->GetX() + 50, cursor->GetY(), script_plr);
|
||||
}
|
||||
|
||||
// Create someone that drops the item while it is on his back
|
||||
if (corpse)
|
||||
{
|
||||
// Kill the Clonk
|
||||
if (corpse->GetAlive())
|
||||
{
|
||||
corpse.silent_death = true; // We don't want sound every time ;)
|
||||
corpse->Kill();
|
||||
Wait(15);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!item)
|
||||
{
|
||||
test.test1_passed[index] = true;
|
||||
test.test1_comment[index] = "Item got removed after death";
|
||||
test.test1_finished[index] = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var attachment_id = 2; // The item is usually attached with this ID, because 1 is the backpack
|
||||
|
||||
if (test.test1_corpse_display[index] == nil)
|
||||
{
|
||||
test.test1_corpse_display[index] = Test1_IsAttached(corpse, attachment_id);
|
||||
}
|
||||
|
||||
if (item->Contained() != collector)
|
||||
{
|
||||
item->SetPosition(collector->GetX(), collector->GetY());
|
||||
collector->Collect(item);
|
||||
Wait(collect_delay);
|
||||
return;
|
||||
}
|
||||
|
||||
if (test.test1_collector_display[index] == nil)
|
||||
{
|
||||
test.test1_collector_display[index] = Test1_IsAttached(collector, attachment_id);
|
||||
}
|
||||
|
||||
test.test1_passed[index] = !test.test1_corpse_display[index] && test.test1_collector_display[index]; // Should not be on the corpse, but on the guy who is holding it
|
||||
test.test1_finished[index] = true;
|
||||
test.test1_comment[index] = Format("Item is displayed: on the corpse (%v), on the collector (%v)", test.test1_corpse_display[index], test.test1_collector_display[index]);
|
||||
}
|
||||
else
|
||||
{
|
||||
test.test1_corpse[index] = corpse = CreateObject(Clonk, cursor->GetX() + 100, cursor->GetY(), script_plr);
|
||||
item->SetPosition(corpse->GetX(), corpse->GetY());
|
||||
corpse->Collect(test.test1_item[index]);
|
||||
corpse->CreateContents(Rock); // Create something else, so that the item is not displayed as a hand item
|
||||
corpse->ShiftContents(nil, Rock);
|
||||
corpse->FindContents(Rock).Visibility = VIS_None;
|
||||
Wait(collect_delay);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
global func Test1_EvaluateResult()
|
||||
{
|
||||
Log(HLINE);
|
||||
Log("Evaluating test 1 for the following definitions");
|
||||
|
||||
var result = true;
|
||||
for (var i = 0; i < GetLength(test.test1_collectible_defs); ++i)
|
||||
{
|
||||
var predicate;
|
||||
if (test.test1_passed[i])
|
||||
{
|
||||
predicate = "Pass";
|
||||
}
|
||||
else
|
||||
{
|
||||
predicate = "Fail";
|
||||
result = false;
|
||||
}
|
||||
|
||||
Log("- [%s] Definition: %i - %s", predicate, test.test1_collectible_defs[i], test.test1_comment[i]);
|
||||
}
|
||||
Log(HLINE);
|
||||
if (!result)
|
||||
{
|
||||
SkipTest();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
global func Test1_IsAttached(object clonk, int attachment)
|
||||
{
|
||||
return clonk->SetAttachTransform(attachment, Trans_Identity()); // Returns false if the attachment does not exist
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
[Teams]
|
||||
Active=1
|
||||
TeamDistribution=Random
|
||||
|
||||
[Team]
|
||||
id=1
|
||||
|
||||
[Team]
|
||||
id=2
|
Loading…
Reference in New Issue