openclonk/planet/Tests.ocf/LiquidSystem.ocs/Script.c

447 lines
12 KiB
C

/**
Liquid System
Unit tests for the liquid system. 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
*/
static script_plr;
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.
var effect = AddEffect("IntTestControl", nil, 100, 2);
effect.testnr = 1;
effect.launched = false;
effect.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.
var effect = GetEffect("IntTestControl", nil);
if (!effect)
{
// Create a new control effect and launch the test.
effect = AddEffect("IntTestControl", nil, 100, 2);
effect.testnr = nr;
effect.launched = false;
effect.plr = GetPlayerByIndex(0, C4PT_User);
return;
}
// Finish the currently running test.
Call(Format("~Test%d_OnFinished", effect.testnr));
// Start the requested test by just setting the test number and setting
// effect.launched to false, effect will handle the rest.
effect.testnr = nr;
effect.launched = false;
return;
}
// Calling this function skips the current test, does not work if last test has been ran already.
global func SkipTest()
{
// Get the control effect.
var effect = GetEffect("IntTestControl", nil);
if (!effect)
return;
// Finish the previous test.
Call(Format("~Test%d_OnFinished", effect.testnr));
// Start the next test by just increasing the test number and setting
// effect.launched to false, effect will handle the rest.
effect.testnr++;
effect.launched = false;
return;
}
/*-- Test Effect --*/
global func FxIntTestControlStart(object target, proplist effect, int temporary)
{
if (temporary)
return FX_OK;
// Set default interval.
effect.Interval = 2;
return FX_OK;
}
global func FxIntTestControlTimer(object target, proplist effect)
{
// Launch new test if needed.
if (!effect.launched)
{
// Log test start.
Log("=====================================");
Log("Test %d started:", effect.testnr);
// Start the test if available, otherwise finish test sequence.
if (!Call(Format("~Test%d_OnStart", effect.testnr), effect.plr))
{
Log("Test %d not available, the previous test was the last test.", effect.testnr);
Log("=====================================");
Log("All tests have been successfully completed!");
return FX_Execute_Kill;
}
effect.launched = true;
}
// Check whether the current test has been finished.
if (Call(Format("Test%d_Completed", effect.testnr)))
{
effect.launched = false;
//RemoveTest();
// Call the test on finished function.
Call(Format("~Test%d_OnFinished", effect.testnr));
// Log result and increase test number.
Log("Test %d successfully completed.", effect.testnr);
effect.testnr++;
}
return FX_OK;
}
/*-- Liquid Tests --*/
global func Test1_OnStart(int plr)
{
var foundry = CreateObjectAbove(Foundry, 110, 160, plr);
foundry->CreateContents(Earth, 10);
foundry->AddToQueue(Loam, 2);
var pump = CreateObjectAbove(Pump, 84, 160, plr);
var source = CreateObjectAbove(Pipe, 168, 292, plr);
source->ConnectPipeTo(pump, PIPE_STATE_Source);
var drain = CreateObjectAbove(Pipe, 240, 100, plr);
drain->ConnectPipeTo(pump, PIPE_STATE_Drain);
drain->ConnectPipeTo(foundry, PIPE_STATE_Drain);
// Log what the test is about.
Log("Water supply to foundry.");
return true;
}
global func Test1_Completed()
{
if (ObjectCount(Find_ID(Loam)) >= 2)
return true;
return false;
}
global func Test1_OnFinished()
{
RemoveAll(Find_Or(Find_ID(Foundry), Find_ID(Pump), Find_ID(Loam)));
RestoreWaterLevels();
return;
}
global func Test2_OnStart(int plr)
{
var foundry = CreateObjectAbove(Foundry, 110, 160, plr);
foundry->CreateContents(Rock, 60);
foundry->AddToQueue(Concrete, nil, true);
var pump = CreateObjectAbove(Pump, 84, 160, plr);
var source = CreateObjectAbove(Pipe, 168, 292, plr);
source->ConnectPipeTo(pump, PIPE_STATE_Source);
var drain = CreateObjectAbove(Pipe, 240, 100, plr);
drain->ConnectPipeTo(pump, PIPE_STATE_Drain);
drain->ConnectPipeTo(foundry, PIPE_STATE_Drain);
var pump = CreateObjectAbove(Pump, 240, 160, plr);
pump->SetResourceSelection([Concrete]);
var source = CreateObjectAbove(Pipe, 168, 292, plr);
source->ConnectPipeTo(pump, PIPE_STATE_Source);
source->ConnectPipeTo(foundry, PIPE_STATE_Source);
var drain = CreateObjectAbove(Pipe, 240, 100, plr);
drain->ConnectPipeTo(pump, PIPE_STATE_Drain);
// Log what the test is about.
Log("Water supply to foundry and concrete supply from foundry.");
return true;
}
global func Test2_Completed()
{
if (GetMaterial(240, 60) == Material("Granite"))
return true;
return false;
}
global func Test2_OnFinished()
{
RemoveAll(Find_Or(Find_ID(Foundry), Find_ID(Pump), Find_ID(Pipe)));
RestoreWaterLevels();
return;
}
global func Test3_OnStart(int plr)
{
DrawMaterialQuad("Oil", 144, 168, 208 + 1, 168, 208 + 1, 304, 144, 304, true);
var engine1 = CreateObjectAbove(SteamEngine, 70, 160, plr);
var engine2 = CreateObjectAbove(SteamEngine, 240, 160, plr);
var pump1 = CreateObjectAbove(Pump, 16, 160, plr);
var pump2 = CreateObjectAbove(Pump, 124, 160, plr);
var source = CreateObjectAbove(Pipe, 168, 292, plr);
source->ConnectPipeTo(pump1, PIPE_STATE_Source);
var drain = CreateObjectAbove(Pipe, 240, 100, plr);
drain->ConnectPipeTo(pump1, PIPE_STATE_Drain);
drain->ConnectPipeTo(engine1, PIPE_STATE_Drain);
var source = CreateObjectAbove(Pipe, 168, 292, plr);
source->ConnectPipeTo(pump2, PIPE_STATE_Source);
source->ConnectPipeTo(engine1, PIPE_STATE_Source);
var drain = CreateObjectAbove(Pipe, 240, 100, plr);
drain->ConnectPipeTo(pump2, PIPE_STATE_Drain);
drain->ConnectPipeTo(engine2, PIPE_STATE_Drain);
// Log what the test is about.
Log("Supply two steam engines with oil in a chain.");
return true;
}
global func Test3_Completed()
{
for (var engine in FindObjects(Find_ID(SteamEngine)))
if (engine->GetLiquidAmount("Oil") < 300)
return false;
return true;
}
global func Test3_OnFinished()
{
RemoveAll(Find_Or(Find_ID(SteamEngine), Find_ID(Pump), Find_ID(Pipe)));
RestoreWaterLevels();
return;
}
global func Test4_OnStart(int plr)
{
DrawMatBasin("DuroLava", 20, 120);
var foundry = CreateObjectAbove(Foundry, 110, 160, plr);
foundry->CreateContents(Earth, 10);
foundry->AddToQueue(Loam, 5);
var pump = CreateObjectAbove(Pump, 84, 160, plr);
var source = CreateObject(Pipe, 168, 292, plr);
source->ConnectPipeTo(pump, PIPE_STATE_Source);
var drain = CreateObjectAbove(Pipe, 240, 100, plr);
drain->ConnectPipeTo(pump, PIPE_STATE_Drain);
drain->ConnectPipeTo(foundry, PIPE_STATE_Drain);
ScheduleCall(source, "SetPosition", 100, 0, 20, 120);
ScheduleCall(foundry, "DoCutPipe", 200, 0, drain);
// Log what the test is about.
Log("Test air switching pumping materials after connection changes.");
return true;
}
global func Test4_Completed()
{
// The test fails if lava is left in the new source rectangle,
// or if production can be completed (the foundry can produce
// only 2 loam instead of 5 if the connection changes)
var could_pump_lava = GetMaterial(20, 125) == Material("Sky");
var cannot_finish_production = ObjectCount(Find_ID(Loam)) <= 2;
var producing = FindObject(Find_ID(Foundry))->IsProducing();
return !producing && could_pump_lava && cannot_finish_production;
}
global func Test4_OnFinished()
{
RemoveAll(Find_Or(Find_ID(Foundry), Find_ID(Pump), Find_ID(Loam)));
RestoreWaterLevels();
return;
}
global func Test5_OnStart(int plr)
{
RemoveAll(Find_ID(Rule_NoPowerNeed));
var engine = CreateObjectAbove(SteamEngine, 40, 160, plr);
engine->CreateContents(Coal, 10);
var pump = CreateObjectAbove(Pump, 84, 160, plr);
var helmet = GetHiRank(plr)->CreateContents(DivingHelmet);
var drain = CreateObjectAbove(Pipe, 240, 100, plr);
drain->ConnectPipeTo(helmet);
drain->ConnectPipeTo(pump, drain->GetPipeState());
// Move player character over the basin
GetHiRank()->SetPosition(175, 150);
GetHiRank()->SetComDir(COMD_Down);
helmet->ControlUse(GetHiRank(plr));
// Log what the test is about.
Log("Test air supply to diving helmet - dive down towards the ground");
return true;
}
global func Test5_Completed()
{
var is_down = GetHiRank()->GetY() > 280;
if (is_down)
{
GetHiRank()->SetComDir(COMD_Up);
var breath_before = GetHiRank()->GetBreath();
GetHiRank()->DoBreath(1000);
var breath_used = GetHiRank().MaxBreath - breath_before;
var pump = FindObject(Find_ID(Pump));
var is_pumping = pump->GetAction() == "Pump";
var has_air_pipe = pump->IsAirPipeConnected();
Log("The clonk used %d air, pump is pumping %v, has air pipe %v", breath_used, is_pumping, has_air_pipe);
if (breath_used <= 70 && is_pumping && has_air_pipe)
{
return true;
}
Log("There was no air supply to the diving helmet - skipping the failed test");
SkipTest();
}
return false;
}
global func Test5_OnFinished()
{
RemoveAll(Find_Or(Find_ID(DivingHelmet), Find_ID(Pump), Find_ID(Pipe), Find_ID(SteamEngine)));
RestoreWaterLevels();
CreateObject(Rule_NoPowerNeed);
return;
}
global func Test6_OnStart(int plr)
{
var tank = CreateObjectAbove(LiquidTank, 70, 160, plr);
var pump1 = CreateObjectAbove(Pump, 16, 160, plr);
var pump2 = CreateObjectAbove(Pump, 124, 160, plr);
var source = CreateObjectAbove(Pipe, 168, 292, plr);
source->ConnectPipeTo(pump1, PIPE_STATE_Source);
var drain = CreateObjectAbove(Pipe, 240, 100, plr);
drain->ConnectPipeTo(pump1, PIPE_STATE_Drain);
drain->ConnectPipeTo(tank, PIPE_STATE_Drain);
var source = CreateObjectAbove(Pipe, 168, 292, plr);
source->ConnectPipeTo(pump2, PIPE_STATE_Source);
source->ConnectPipeTo(tank, PIPE_STATE_Source);
var drain = CreateObjectAbove(Pipe, 240, 100, plr);
drain->ConnectPipeTo(pump2, PIPE_STATE_Drain);
// Log what the test is about.
Log("Test pumping into and from a liquid tank");
return true;
}
global func Test6_Completed()
{
if (GetMaterial(240, 60) == Material("Water"))
return true;
return false;
}
global func Test6_OnFinished()
{
RemoveAll(Find_Or(Find_ID(LiquidTank), Find_ID(Pump), Find_ID(Pipe)));
RestoreWaterLevels();
return;
}
/*-- Helper Functions --*/
global func RestoreWaterLevels()
{
// Restore water levels.
DrawMaterialQuad("Water", 144, 168, 208 + 1, 168, 208 + 1, 304, 144, 304, true);
for (var x = 216; x <= 280; x++)
for (var y = 24; y <= 120; y++)
if (GetMaterial(x, y) != Material("BrickSoft"))
ClearFreeRect(x, y, 1, 1);
return;
}
global func DrawMatBasin(string mat, int x, int y)
{
DrawMaterialQuad("Brick", x - 10, y - 10, x - 10, y + 10, x + 10, y + 10, x + 10, y - 10);
DrawMaterialQuad(mat, x - 6, y - 6, x - 6, y + 6, x + 6, y + 6, x + 6, y - 6);
return;
}
global func RemoveWater()
{
for (var x = 144; x <= 208 + 1; x++)
for (var y = 168; y <= 304; y++)
if (GetMaterial(x, y) != Material("BrickSoft"))
ClearFreeRect(x, y, 1, 1);
return;
}