forked from Mirrors/openclonk
fixed no power need rule
parent
750945ee1c
commit
a5155f6d88
|
@ -9,6 +9,7 @@
|
|||
with the network by using the functions:
|
||||
* RegisterPowerRequest(int amount)
|
||||
* UnregisterPowerRequest()
|
||||
* UpdatePowerRequest() - used internally only.
|
||||
The network will then continously search for available power to deliver to
|
||||
this consumer and will notify it via the callbacks
|
||||
* OnEnoughPower(int amount)
|
||||
|
@ -30,9 +31,13 @@
|
|||
Using the callback GetActualPowerConsumer() the power consumption of an object
|
||||
can be passed to its main structure.
|
||||
|
||||
The consumer does not consume power if the Rule_NoPowerNeed is active, to set
|
||||
the need for power on a per consumer basis you can use the function
|
||||
SetNoPowerNeed(bool no_need).
|
||||
|
||||
Important notes when including this library:
|
||||
* The object including this library should return _inherited(...) in the
|
||||
Destruction callback if overloaded.
|
||||
Initialize and Destruction callback if overloaded.
|
||||
|
||||
@author Zapper, Maikel
|
||||
*/
|
||||
|
@ -60,6 +65,14 @@ private func UnregisterPowerRequest()
|
|||
return;
|
||||
}
|
||||
|
||||
// Call this function in the power consuming structure to request and update from
|
||||
// the power network of this consumer.
|
||||
private func UpdatePowerRequest()
|
||||
{
|
||||
Library_Power->UpdateForPowerLink(this);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*-- Callbacks --*/
|
||||
|
||||
|
@ -100,6 +113,23 @@ public func GetActualPowerConsumer()
|
|||
|
||||
/*-- Library Code --*/
|
||||
|
||||
// All power related local variables are stored in a single proplist.
|
||||
// This reduces the chances of clashing local variables. See
|
||||
// Initialize for which variables are being used.
|
||||
local lib_power;
|
||||
|
||||
// Initialize callback by the engine: check whether the no power need rule is active.
|
||||
protected func Initialize()
|
||||
{
|
||||
// Initialize the single proplist for the power consumer library.
|
||||
if (lib_power == nil)
|
||||
lib_power = {};
|
||||
// A single variable to keep track whether power is needed.
|
||||
// Power is not needed when the no power need rule is active.
|
||||
lib_power.power_need = ObjectCount(Find_ID(Rule_NoPowerNeed)) == 0;
|
||||
return _inherited(...);
|
||||
}
|
||||
|
||||
// Destruction callback by the engine: let power network know this object is not
|
||||
// a consumer anymore, it must always be unregistered from the power network.
|
||||
protected func Destruction()
|
||||
|
@ -107,3 +137,20 @@ protected func Destruction()
|
|||
UnregisterPowerRequest();
|
||||
return _inherited(...);
|
||||
}
|
||||
|
||||
// By calling this function you can make this consumer ignore the power need. This is
|
||||
// used by the power need rule and can be used by scripters to temporarily turn off the
|
||||
// need for power in a certain consumer.
|
||||
public func SetNoPowerNeed(bool no_need)
|
||||
{
|
||||
lib_power.power_need = !no_need;
|
||||
// Make sure the power balance of the network is updated.
|
||||
UpdatePowerRequest();
|
||||
return;
|
||||
}
|
||||
|
||||
// Returns whether this consumer has a power need or not.
|
||||
public func HasPowerNeed()
|
||||
{
|
||||
return lib_power.power_need;
|
||||
}
|
||||
|
|
|
@ -50,7 +50,8 @@ local lib_power;
|
|||
protected func Initialize()
|
||||
{
|
||||
// Initialize the single proplist for the power library.
|
||||
lib_power = {};
|
||||
if (lib_power == nil)
|
||||
lib_power = {};
|
||||
// Initialize producer and consumer lists.
|
||||
// Lists to keep track of the producers and consumers.
|
||||
lib_power.idle_producers = [];
|
||||
|
@ -118,6 +119,18 @@ public func UnregisterPowerConsumer(object consumer)
|
|||
return;
|
||||
}
|
||||
|
||||
// Definition call: updates the network for this power link.
|
||||
public func UpdateForPowerLink(object link)
|
||||
{
|
||||
// Definition call safety checks.
|
||||
if (this != Library_Power || !link)
|
||||
return FatalError("UpdateForPowerLink() either not called from definition context or no link specified.");
|
||||
// Find the network for this link and update it.
|
||||
var network = GetPowerNetwork(link);
|
||||
network->CheckPowerBalance();
|
||||
return;
|
||||
}
|
||||
|
||||
// Definition call: gives the power helper object.
|
||||
// TODO: Clean up this code!
|
||||
public func GetPowerNetwork(object for_obj)
|
||||
|
@ -126,17 +139,22 @@ public func GetPowerNetwork(object for_obj)
|
|||
if (this != Library_Power || !for_obj)
|
||||
return FatalError("GetPowerNetwork() either not called from definition context or no object specified.");
|
||||
|
||||
var w;
|
||||
while (w = for_obj->~GetActualPowerConsumer())
|
||||
// Get the actual power consumer for this object. This can for example be the elevator for the case.
|
||||
var actual;
|
||||
while (actual = for_obj->~GetActualPowerConsumer())
|
||||
{
|
||||
if (w == for_obj)
|
||||
break; // nope
|
||||
for_obj = w;
|
||||
// Stop a possible infinite loop.
|
||||
if (actual == for_obj)
|
||||
break;
|
||||
for_obj = actual;
|
||||
}
|
||||
// Get the flag corresponding to the object.
|
||||
var flag = GetFlagpoleForPosition(for_obj->GetX() - GetX(), for_obj->GetY() - GetY());
|
||||
|
||||
// Find the network helper object for this flag.
|
||||
var helper = nil;
|
||||
if (!flag) // neutral - needs neutral helper
|
||||
// If no flag was available the object is neutral and needs a neutral helper.
|
||||
if (!flag)
|
||||
{
|
||||
for (var network in LIB_POWR_Networks)
|
||||
{
|
||||
|
@ -145,18 +163,19 @@ public func GetPowerNetwork(object for_obj)
|
|||
helper = network;
|
||||
break;
|
||||
}
|
||||
|
||||
if (helper == nil) // not yet created?
|
||||
// Create the helper if it does not exist yet.
|
||||
if (helper == nil)
|
||||
{
|
||||
helper = CreateObject(Library_Power, 0, 0, NO_OWNER);
|
||||
helper.lib_power.neutral_network = true;
|
||||
LIB_POWR_Networks[GetLength(LIB_POWR_Networks)] = helper;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Otherwise just get the helper from the flag.
|
||||
else
|
||||
{
|
||||
helper=flag->GetPowerHelper();
|
||||
|
||||
// Create the helper if it does not exist yet.
|
||||
if (helper == nil)
|
||||
{
|
||||
helper = CreateObject(Library_Power, 0, 0, NO_OWNER);
|
||||
|
@ -165,9 +184,9 @@ public func GetPowerNetwork(object for_obj)
|
|||
flag->SetPowerHelper(helper);
|
||||
for (var f in flag->GetLinkedFlags())
|
||||
{
|
||||
// Assert different power helpers for same compound.
|
||||
// Assert different power helpers for the same network.
|
||||
if (f->GetPowerHelper() != nil)
|
||||
FatalError("Flags in compound have different power helper!");
|
||||
FatalError("Flags in the same network have different power helpers.");
|
||||
f->SetPowerHelper(helper);
|
||||
}
|
||||
}
|
||||
|
@ -305,7 +324,9 @@ public func AddPowerConsumer(object consumer, int amount, int prio)
|
|||
if (link.cons_amount != amount || link.priority != prio)
|
||||
{
|
||||
lib_power.active_consumers[index] = {obj = consumer, cons_amount = amount, priority = prio};
|
||||
VisualizePowerChange(link.obj, link.cons_amount, amount, false);
|
||||
// Only visualize the power change if the consumer had a real power need.
|
||||
if (link.obj->HasPowerNeed())
|
||||
VisualizePowerChange(link.obj, link.cons_amount, amount, false);
|
||||
// Check the power balance of this network, since a change has been made.
|
||||
CheckPowerBalance();
|
||||
}
|
||||
|
@ -345,7 +366,9 @@ public func RemovePowerConsumer(object consumer)
|
|||
RemoveArrayIndex(lib_power.active_consumers, index);
|
||||
// Check the power balance of this network, since a change has been made.
|
||||
CheckPowerBalance();
|
||||
VisualizePowerChange(link.obj, link.cons_amount, 0, true);
|
||||
// Only visualize the power change if the consumer had a real power need.
|
||||
if (link.obj->HasPowerNeed())
|
||||
VisualizePowerChange(link.obj, link.cons_amount, 0, true);
|
||||
return;
|
||||
}
|
||||
// If found in neither lists just return without doing anything.
|
||||
|
@ -355,7 +378,7 @@ public func RemovePowerConsumer(object consumer)
|
|||
// Checks the power balance after a change to this network: i.e. removal or addition
|
||||
// of a consumer or producer. The producers and consumers will be refreshed such that
|
||||
// the ones with highest priority will be active.
|
||||
private func CheckPowerBalance()
|
||||
public func CheckPowerBalance()
|
||||
{
|
||||
// First determine whether the storage links in this network need to be producers
|
||||
// or may be consumers. Get the power needed by all non-storage consumers and the
|
||||
|
@ -437,9 +460,13 @@ private func RefreshConsumers(int power_available)
|
|||
var link = all_consumers[index];
|
||||
if (!link)
|
||||
continue;
|
||||
// Determine the consumption of this consumer, taking into account the power need.
|
||||
var consumption = link.cons_amount;
|
||||
if (!link.obj->HasPowerNeed())
|
||||
consumption = 0;
|
||||
// Too much power has been used, check if this link was active, if so remove from active.
|
||||
// Or if the links is a power storage and there is other storage actively producing remove as well.
|
||||
if (power_used + link.cons_amount > power_available || (link.obj->~IsPowerStorage() && HasProducingStorage()))
|
||||
if (power_used + consumption > power_available || (link.obj->~IsPowerStorage() && HasProducingStorage()))
|
||||
{
|
||||
var idx = GetIndexOf(lib_power.active_consumers, link);
|
||||
if (idx != -1)
|
||||
|
@ -447,22 +474,22 @@ private func RefreshConsumers(int power_available)
|
|||
PushBack(lib_power.waiting_consumers, link);
|
||||
RemoveArrayIndex(lib_power.active_consumers, idx);
|
||||
// On not enough power callback to the deactivated consumer.
|
||||
link.obj->OnNotEnoughPower(link.cons_amount);
|
||||
VisualizePowerChange(link.obj, link.cons_amount, 0, true);
|
||||
link.obj->OnNotEnoughPower(consumption);
|
||||
VisualizePowerChange(link.obj, consumption, 0, true);
|
||||
}
|
||||
}
|
||||
// In the other case see if consumer is not yet active, if so activate.
|
||||
else
|
||||
{
|
||||
power_used += link.cons_amount;
|
||||
power_used += consumption;
|
||||
var idx = GetIndexOf(lib_power.waiting_consumers, link);
|
||||
if (idx != -1)
|
||||
{
|
||||
PushBack(lib_power.active_consumers, link);
|
||||
RemoveArrayIndex(lib_power.waiting_consumers, idx);
|
||||
// On enough power callback to the activated consumer.
|
||||
link.obj->OnEnoughPower(link.cons_amount);
|
||||
VisualizePowerChange(link.obj, 0, link.cons_amount, false);
|
||||
link.obj->OnEnoughPower(consumption);
|
||||
VisualizePowerChange(link.obj, 0, consumption, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -476,7 +503,8 @@ private func GetPowerConsumption()
|
|||
for (var index = GetLength(lib_power.active_consumers) - 1; index >= 0; index--)
|
||||
{
|
||||
var link = lib_power.active_consumers[index];
|
||||
if (!link)
|
||||
// If the link does not exist or has no power need, just continue.
|
||||
if (!link || !link.obj->HasPowerNeed())
|
||||
continue;
|
||||
total += link.cons_amount;
|
||||
}
|
||||
|
@ -491,7 +519,8 @@ private func GetPowerConsumptionNeed()
|
|||
for (var index = GetLength(all_consumers) - 1; index >= 0; index--)
|
||||
{
|
||||
var link = all_consumers[index];
|
||||
if (!link || link.obj->~IsPowerStorage())
|
||||
// If the link does not exist, is a power storage or has no power need, just continue.
|
||||
if (!link || link.obj->~IsPowerStorage() || !link.obj->HasPowerNeed())
|
||||
continue;
|
||||
total += link.cons_amount;
|
||||
}
|
||||
|
|
|
@ -92,12 +92,17 @@ public func GetStoredPower()
|
|||
protected func Initialize()
|
||||
{
|
||||
// Initialize the single proplist for the power storage library.
|
||||
lib_power = {};
|
||||
if (lib_power == nil)
|
||||
lib_power = {};
|
||||
// A single variable to keep track of the stored power in the storage.
|
||||
lib_power.stored_power = 0;
|
||||
// Register as a power consumer since it has zero stored energy.
|
||||
RegisterPowerRequest(GetStoragePower());
|
||||
return _inherited(...);
|
||||
// Now perform the consumer library's initialization.
|
||||
_inherited(...);
|
||||
// Then set the power need for power storages always to true.
|
||||
lib_power.power_need = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Destruction callback by the engine: let power network know this object is not
|
||||
|
@ -108,6 +113,18 @@ protected func Destruction()
|
|||
return _inherited(...);
|
||||
}
|
||||
|
||||
// Overload the consumer library's no power need function to do nothing.
|
||||
public func SetNoPowerNeed(bool no_need)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Returns that a storage always has a power need.
|
||||
public func HasPowerNeed()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Cooldown effect to prevent continuous switching between consumption and production.
|
||||
protected func FxCoolDownStart(object target, proplist effect, int temp)
|
||||
{
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
/**
|
||||
No Energy Rule
|
||||
If this rule is activated, power consumers do not need energy supply
|
||||
anymore to operate.
|
||||
anymore to operate. This rule informs existing consumers about its
|
||||
presence and removal. Consumers created while this rule is active
|
||||
will themselves set the no power need.
|
||||
|
||||
@author Zapper, Maikel
|
||||
*/
|
||||
|
@ -12,89 +14,22 @@ protected func Initialize()
|
|||
// Don't do anything if this is not the first rule of this type.
|
||||
if (ObjectCount(Find_ID(Rule_NoPowerNeed)) > 1)
|
||||
return;
|
||||
|
||||
// If there are no power consumers yet, there is nothing to be done.
|
||||
if (LIB_POWR_Networks == nil)
|
||||
return;
|
||||
|
||||
// Update all consumers forcefully.
|
||||
var remember = [];
|
||||
|
||||
// Get all power compounds (bases).
|
||||
for (var base in LIB_POWR_Networks)
|
||||
{
|
||||
// Iterate through all registered consumers & producers, these are not the sleeping power links.
|
||||
for (var i = GetLength(base.power_links) - 1; i >= 0; --i)
|
||||
{
|
||||
var obj_data = base.power_links[i];
|
||||
if (obj_data == nil)
|
||||
continue;
|
||||
// If it is a power producer, continue to next link.
|
||||
if (!obj_data.obj->~CurrentlyHasPower() || obj_data.amount > 0)
|
||||
continue;
|
||||
|
||||
// Temporarily stop consuming power to make sure the callback order is correct.
|
||||
obj_data.obj->~OnNotEnoughPower();
|
||||
|
||||
// Power consumer behavior.
|
||||
obj_data.obj.last_request = 0;
|
||||
var lpr_a = obj_data.obj.last_amount;
|
||||
obj_data.obj.last_amount = 0;
|
||||
|
||||
// Remove from list.
|
||||
RemoveArrayIndexUnstable(base.power_links, i);
|
||||
|
||||
// Make new power consumer later.
|
||||
PushBack(remember, {obj = obj_data.obj, amount = lpr_a});
|
||||
}
|
||||
|
||||
// Now awake the sleeping links, after the consumers.
|
||||
for (var i = GetLength(base.sleeping_links) - 1; i >= 0; --i)
|
||||
{
|
||||
var obj_data = base.sleeping_links[i];
|
||||
PushBack(remember, {obj = obj_data.obj, amount = obj_data.amount});
|
||||
}
|
||||
// Reset the sleeping links to an empty list.
|
||||
base.sleeping_links = [];
|
||||
}
|
||||
|
||||
// Let all remembered consumers consume again!
|
||||
for (var obj_data in remember)
|
||||
{
|
||||
if (obj_data == nil)
|
||||
continue;
|
||||
obj_data.obj->MakePowerConsumer(Abs(obj_data.amount));
|
||||
}
|
||||
// Find all consumers and tell them to have no power need.
|
||||
for (var consumer in FindObjects(Find_Func("IsPowerConsumer")))
|
||||
consumer->SetNoPowerNeed(true);
|
||||
return;
|
||||
}
|
||||
|
||||
protected func Destruction()
|
||||
{
|
||||
// If this is not the last copy of this rule do nothing.
|
||||
if (ObjectCount(Find_ID(Rule_NoPowerNeed)) >= 1)
|
||||
if (ObjectCount(Find_ID(Rule_NoPowerNeed)) > 1)
|
||||
return;
|
||||
|
||||
// Schedule the a destruction definition call so that the removal is complete.
|
||||
Schedule(nil, "Rule_NoPowerNeed->DestructionEx()", 1);
|
||||
return;
|
||||
}
|
||||
|
||||
public func DestructionEx()
|
||||
{
|
||||
// Only perform resetting the links if there are no more rule objects active.
|
||||
if (ObjectCount(Find_ID(Rule_NoPowerNeed)) >= 1)
|
||||
return;
|
||||
|
||||
// Update all consumers again by going through all existing consumers.
|
||||
for (var obj in FindObjects(Find_Func("IsPowerConsumer")))
|
||||
{
|
||||
var request = obj.last_request;
|
||||
var amount = obj.last_amount;
|
||||
// Temporarily stop consuming power to make sure the callback order is correct.
|
||||
obj->OnNotEnoughPower();
|
||||
obj.last_amount = 0;
|
||||
obj->MakePowerConsumer(amount);
|
||||
}
|
||||
// Find all consumers and tell them to have power need again.
|
||||
for (var consumer in FindObjects(Find_Func("IsPowerConsumer")))
|
||||
consumer->SetNoPowerNeed(false);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ protected func Initialize()
|
|||
|
||||
front->SetAction("Attach", this);
|
||||
back->SetAction("Attach", this);
|
||||
return _inherited(...);
|
||||
}
|
||||
|
||||
// Called by the elevator
|
||||
|
|
|
@ -42,6 +42,7 @@ func Initialize()
|
|||
var end = GetAnimationLength("pump");
|
||||
animation = PlayAnimation("pump", 5, Anim_Linear(GetAnimationPosition(animation), start, end, 35, ANIM_Loop), Anim_Const(1000));
|
||||
SetState("Wait");
|
||||
return _inherited(...);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ protected func Initialize()
|
|||
{
|
||||
// Create a script player for some tests.
|
||||
script_plr = nil;
|
||||
CreateScriptPlayer("Buddy", RGB(0, 0, 255), nil, CSPF_NoEliminationCheck);
|
||||
CreateScriptPlayer("PowerBuddy", RGB(0, 0, 255), nil, CSPF_NoEliminationCheck);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -643,7 +643,7 @@ global func Test11_OnStart(int plr)
|
|||
ScheduleCall(nil, "EliminatePlayer", 6 * 36, 0, script_plr);
|
||||
|
||||
// Rejoin the script player for other tests.
|
||||
ScheduleCall(nil, "CreateScriptPlayer", 9 * 36, 0, "Buddy", RGB(0, 0, 255), nil, CSPF_NoEliminationCheck);
|
||||
ScheduleCall(nil, "CreateScriptPlayer", 9 * 36, 0, "PowerBuddy", RGB(0, 0, 255), nil, CSPF_NoEliminationCheck);
|
||||
|
||||
// Log what the test is about.
|
||||
Log("Test connecting two networks by different allied players and then elimination of one player.");
|
||||
|
@ -664,8 +664,56 @@ global func Test11_OnFinished()
|
|||
return;
|
||||
}
|
||||
|
||||
// Test for the supported infinite pump loop, with two pumps pumping in opposite directions.
|
||||
// Test for the no power need rule.
|
||||
global func Test12_OnStart(int plr)
|
||||
{
|
||||
// Power source: one steam engine.
|
||||
var steam_engine = CreateObjectAbove(SteamEngine, 40, 160, plr);
|
||||
steam_engine->CreateContents(Coal, 4);
|
||||
|
||||
// Power consumers: one workshop, one inventor's lab.
|
||||
var workshop = CreateObjectAbove(ToolsWorkshop, 110, 160, plr);
|
||||
workshop->CreateContents(Wood, 4);
|
||||
workshop->CreateContents(Metal, 4);
|
||||
workshop->AddToQueue(Shovel, 4);
|
||||
var lab = CreateObjectAbove(InventorsLab, 450, 248, plr);
|
||||
lab->CreateContents(Metal, 8);
|
||||
lab->AddToQueue(TeleGlove, 4);
|
||||
lab->SetNoPowerNeed(true);
|
||||
|
||||
// Power connection: flagpole.
|
||||
CreateObjectAbove(Flagpole, 304, 140, plr);
|
||||
|
||||
// Create the no power need rule.
|
||||
ScheduleCall(nil, "CreateObject", 3 * 36, 0, Rule_NoPowerNeed);
|
||||
|
||||
// Let the lab consumer power again.
|
||||
ScheduleCall(lab, "SetNoPowerNeed", 6 * 36, 0, false);
|
||||
|
||||
// Remove the no power need rule.
|
||||
Schedule(nil, "RemoveAll(Find_ID(Rule_NoPowerNeed))", 9 * 36, 0);
|
||||
|
||||
// Log what the test is about.
|
||||
Log("Test for the no power need rule.");
|
||||
return true;
|
||||
}
|
||||
|
||||
global func Test12_Completed()
|
||||
{
|
||||
if (ObjectCount(Find_ID(Shovel)) >= 4 && ObjectCount(Find_ID(TeleGlove)) >= 4)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
global func Test12_OnFinished()
|
||||
{
|
||||
// Remove wind generator, steam engine, flagpole, shipyard, airship.
|
||||
RemoveAll(Find_Or(Find_ID(SteamEngine), Find_ID(ToolsWorkshop), Find_ID(InventorsLab)));
|
||||
return;
|
||||
}
|
||||
|
||||
// Test for the supported infinite pump loop, with two pumps pumping in opposite directions.
|
||||
global func Test13_OnStart(int plr)
|
||||
{
|
||||
// Power source: wind generator producing the power difference between the two pumps.
|
||||
SetWindFixed(10);
|
||||
|
@ -694,14 +742,14 @@ global func Test12_OnStart(int plr)
|
|||
return true;
|
||||
}
|
||||
|
||||
global func Test12_Completed()
|
||||
global func Test13_Completed()
|
||||
{
|
||||
if (GetMaterial(248, 48) == Material("Water"))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
global func Test12_OnFinished()
|
||||
global func Test13_OnFinished()
|
||||
{
|
||||
// Restore water levels.
|
||||
DrawMaterialQuad("Water", 144, 168, 208 + 1, 168, 208 + 1, 304, 144, 304, true);
|
||||
|
|
Loading…
Reference in New Issue