forked from Mirrors/openclonk
new power system (work in progress)
parent
a237caa467
commit
2d00588dff
|
@ -28,40 +28,39 @@ func FxScheduleRefreshAllPowerHelpersTimer()
|
|||
return -1;
|
||||
}
|
||||
|
||||
// Refreshes all power networks (Library_Power objects).
|
||||
func RefreshAllPowerHelpers()
|
||||
{
|
||||
// no power helpers created yet
|
||||
if(GetType(Library_Power_power_compounds) != C4V_Array)
|
||||
// Don't do anything if there are no power helpers created yet.
|
||||
if (GetType(LIB_POWR_Networks) != C4V_Array)
|
||||
return;
|
||||
|
||||
// special handling for neutral
|
||||
var neutral = nil;
|
||||
for(var obj in Library_Power_power_compounds)
|
||||
// Special handling for neutral networks of which there is only at most one.
|
||||
var neutral_network = nil;
|
||||
for (var network in LIB_POWR_Networks)
|
||||
{
|
||||
if(!obj || !obj.neutral) continue;
|
||||
neutral = obj;
|
||||
if (!network || !network.lib_neutral_network) continue;
|
||||
neutral_network = network;
|
||||
break;
|
||||
}
|
||||
if (neutral_network)
|
||||
RefreshPowerHelper(neutral_network);
|
||||
|
||||
if(neutral)
|
||||
// Do the same for all other helpers: delete / refresh.
|
||||
for (var i = GetLength(LIB_POWR_Networks) - 1; i >= 0; i--)
|
||||
{
|
||||
RefreshPowerHelper(neutral);
|
||||
}
|
||||
|
||||
// same for all helpers - delete / refresh
|
||||
for(var i = GetLength(Library_Power_power_compounds); --i >= 0;)
|
||||
{
|
||||
var obj = Library_Power_power_compounds[i];
|
||||
if (!obj) continue;
|
||||
if(GetLength(obj.power_links) == 0 && GetLength(obj.sleeping_links) == 0)
|
||||
{
|
||||
obj->RemoveObject();
|
||||
Library_Power_power_compounds[i] = Library_Power_power_compounds[GetLength(Library_Power_power_compounds) - 1];
|
||||
SetLength(Library_Power_power_compounds, GetLength(Library_Power_power_compounds) - 1);
|
||||
var network = LIB_POWR_Networks[i];
|
||||
if (!network)
|
||||
continue;
|
||||
}
|
||||
|
||||
obj->CheckPowerBalance();
|
||||
/*if (GetLength(network.power_links) == 0 && GetLength(network.sleeping_links) == 0)
|
||||
{
|
||||
network->RemoveObject();
|
||||
LIB_POWR_Networks[i] = LIB_POWR_Networks[GetLength(LIB_POWR_Networks) - 1];
|
||||
SetLength(LIB_POWR_Networks, GetLength(LIB_POWR_Networks) - 1);
|
||||
continue;
|
||||
}*/
|
||||
network->CheckPowerBalance();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -334,8 +333,8 @@ func RefreshLinkedFlags()
|
|||
// since we don't know whether flag links have been lost we will create a new power helper and possibly remove old ones
|
||||
Library_Power->Init(); // make sure the power system is set up
|
||||
var old = lflag.power_helper;
|
||||
lflag.power_helper = CreateObjectAbove(Library_Power, 0, 0, NO_OWNER);
|
||||
Library_Power_power_compounds[GetLength(Library_Power_power_compounds)] = lflag.power_helper;
|
||||
lflag.power_helper = CreateObject(Library_Power, 0, 0, NO_OWNER);
|
||||
LIB_POWR_Networks[GetLength(LIB_POWR_Networks)] = lflag.power_helper;
|
||||
|
||||
// list of helpers yet to merge
|
||||
var to_merge = [old];
|
||||
|
@ -364,29 +363,29 @@ func RefreshLinkedFlags()
|
|||
func RefreshPowerHelper(h)
|
||||
{
|
||||
// merge both power_links and sleeping_links
|
||||
for(var o in h.power_links)
|
||||
/*for(var o in h.power_links)
|
||||
{
|
||||
if(o == nil) continue; // possible
|
||||
|
||||
var actual = Library_Power->GetPowerHelperForObject(o.obj);
|
||||
var actual = Library_Power->GetPowerNetwork(o.obj);
|
||||
if (!actual) continue;
|
||||
if(actual == h) continue; // right one already
|
||||
if (actual == h) continue; // right one already
|
||||
// remove from old and add to new
|
||||
h->RemovePowerLink(o.obj, true);
|
||||
//h->RemovePowerLink(o.obj, true);
|
||||
actual->AddPowerLink(o.obj, o.amount, true);
|
||||
}
|
||||
|
||||
for(var i = GetLength(h.sleeping_links); --i >= 0;)
|
||||
for (var i = GetLength(h.sleeping_links); --i >= 0;)
|
||||
{
|
||||
var o = h.sleeping_links[i];
|
||||
var actual = Library_Power->GetPowerHelperForObject(o.obj);
|
||||
var actual = Library_Power->GetPowerNetwork(o.obj);
|
||||
if(actual == h) continue; // right one already
|
||||
// remove from old one and add to new
|
||||
actual.sleeping_links[GetLength(actual.sleeping_links)] = o;
|
||||
|
||||
h.sleeping_links[i] = h.sleeping_links[GetLength(h.sleeping_links) - 1];
|
||||
SetLength(h.sleeping_links, GetLength(h.sleeping_links) - 1);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
public func CopyLinkedFlags(object from, array flaglist)
|
||||
|
|
|
@ -1,194 +1,108 @@
|
|||
/**
|
||||
Power Consumer
|
||||
Handles some aspects of power producing structures, this library
|
||||
should be included by all power producing structures.
|
||||
Handles some aspects of power consuming structures, this library should be
|
||||
included by all power consuming structures. Certain functions should be
|
||||
overloaded and others can be used to implement the consumption of power in
|
||||
a uniform way consistent with the network, see text below.
|
||||
|
||||
Cares about showing the "No Power"-symbol
|
||||
and provides CurrentlyHasPower()
|
||||
also handles requesting 0 power and the NoPowerNeed-rule correctly
|
||||
The interfact is built up such that the consumer can make a request for power
|
||||
with the network by using the functions:
|
||||
* RegisterPowerRequest(int amount)
|
||||
* UnregisterPowerRequest()
|
||||
The network will then continously search for available power to deliver to
|
||||
this consumer and will notify it via the callbacks
|
||||
* OnEnoughPower(int amount)
|
||||
* OnNotEnoughPower()
|
||||
The last callback will be called when the consumer had enough power and the
|
||||
network stopped delivering to this consumer, due to whatever reason except
|
||||
the consumer itself unregistering the request for power.
|
||||
|
||||
The main part of the power system is handled by Library_Power
|
||||
The consumer structures can overload the function GetConsumerPriority() and
|
||||
return the priority for power requests. The library will deliver power
|
||||
preferentially to consumers with higher priority. In this way certain
|
||||
consumers can be prioritized over others. Typical return values are:
|
||||
* Pump 25
|
||||
* Workshop: 50
|
||||
* Elevator: 100
|
||||
See also the scripts of these structures for more details on the usage of the
|
||||
power consumer library.
|
||||
|
||||
Usage:
|
||||
a power consumer should always include this library.
|
||||
production (or anything else) should /only/ be started or continued in the callback OnEnoughPower.
|
||||
in the callback OnNotEnoughPower the user should pause the production.
|
||||
Using the callback GetActualPowerConsumer() the power consumption of an object
|
||||
can be passed to its main structure.
|
||||
|
||||
when everything is ready to produce the user should call MakePowerConsumer(amount) where amount is the amount of power to request (works with 0).
|
||||
when the production is done or the building wants to cease consuming power, it should call UnmakePowerConsumer() - note that the callback OnNotEnoughPower is not called this way.
|
||||
|
||||
other:
|
||||
the callback GetActualPowerConsumer can return another object that acts as the power consumer when checking for the affiliation to a flag. For example the elevator case could be the power consumer but use the elevator building as the actual power consumer.
|
||||
CurrentlyHasPower() returns true when the object has requested power and is not in the sleeping queue.
|
||||
Note that the object including this library should return _inherited(...) in
|
||||
the Destruction callback if overloaded.
|
||||
|
||||
@author Zapper, Maikel
|
||||
*/
|
||||
|
||||
// Local variables to track power requests and amount.
|
||||
local has_power = false;
|
||||
local last_request = 0;
|
||||
local last_amount = 0;
|
||||
|
||||
// States for being able to handle 0-power requests.
|
||||
static const PowerConsumer_LPR_None = 0;
|
||||
static const PowerConsumer_LPR_Zero = 1;
|
||||
static const PowerConsumer_LPR_NonZero = 2;
|
||||
|
||||
|
||||
// This object is a power consumer.
|
||||
public func IsPowerConsumer() { return true; }
|
||||
|
||||
|
||||
/*-- Interface --*/
|
||||
|
||||
// Call this function in the power consuming structure to indicate to the network
|
||||
// a request for power of the specified amount.
|
||||
private func RegisterPowerRequest(int amount)
|
||||
{
|
||||
Library_Power->RegisterPowerConsumer(this, amount);
|
||||
return;
|
||||
}
|
||||
|
||||
// Call this function in the power consuming structure to indicate to the network
|
||||
// a the end of a power request.
|
||||
private func UnregisterPowerRequest()
|
||||
{
|
||||
Library_Power->UnregisterPowerConsumer(this);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*-- Callbacks --*/
|
||||
|
||||
// Callback by the power network. Overload this function to start the consumers
|
||||
// functionality, since enough power is available. return inherited(amount, ...)
|
||||
// to remove the no-power symbol. It is not allowed to (un)register a power request
|
||||
// in this callback.
|
||||
public func OnEnoughPower()
|
||||
{
|
||||
// Remove the no-power symbol.
|
||||
RemoveStatusSymbol(Library_PowerConsumer);
|
||||
return;
|
||||
}
|
||||
|
||||
// Callback by the power network. Overload this function to stop the consumers
|
||||
// functionality, since not enough power is available. return inherited(amount, ...)
|
||||
// to add the no-power symbol. It is not allowed to (un)register a power request
|
||||
// in this callback.
|
||||
public func OnNotEnoughPower()
|
||||
{
|
||||
// Show the no-power symbol.
|
||||
AddStatusSymbol(Library_PowerConsumer);
|
||||
return;
|
||||
}
|
||||
|
||||
// Consumer priority: the need of a consumer to have power. This can be used
|
||||
// by the structures to prioritize certain consumption, for example letting
|
||||
// an elevator be dominant over a pump.
|
||||
public func GetConsumerPriority() { return 0; }
|
||||
|
||||
public func CurrentlyHasPower()
|
||||
{
|
||||
return has_power;
|
||||
}
|
||||
|
||||
|
||||
/*-- Interface --*/
|
||||
|
||||
// Is the object just a part of a building? For example elevator and its case.
|
||||
// This callback may return an object which acts as the actual power consumer. For example
|
||||
// the elevator case may return the main elevator object as the main consumer.
|
||||
public func GetActualPowerConsumer()
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
// How much would you like to withdraw your power request?
|
||||
// Normal objects: not so much, battery: very much.
|
||||
public func QueryWaivePowerRequest()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The object requested power but there is no power!
|
||||
// Should possibly not use MakePowerConsumer/Producer in this callback.
|
||||
public func OnNotEnoughPower()
|
||||
{
|
||||
has_power = false;
|
||||
// Show symbol.
|
||||
this->AddStatusSymbol(Library_PowerConsumer);
|
||||
return;
|
||||
}
|
||||
/*-- Library Code --*/
|
||||
|
||||
// called when the object was deleted from the sleeping queue
|
||||
// that means, the object had requested power before
|
||||
public func OnRemovedFromPowerSleepingQueue()
|
||||
{
|
||||
// Remove symbol.
|
||||
this->RemoveStatusSymbol(Library_PowerConsumer);
|
||||
return;
|
||||
}
|
||||
|
||||
// Called when consumer was sleeping but power is available again.
|
||||
// Should possibly not use MakePowerConsumer/Producer in this callback.
|
||||
public func OnEnoughPower()
|
||||
{
|
||||
has_power = true;
|
||||
// Remove symbol.
|
||||
this->RemoveStatusSymbol(Library_PowerConsumer);
|
||||
return;
|
||||
}
|
||||
|
||||
// Add/Remove an effect such that this structure does not need power
|
||||
public func SetNoPowerNeed(bool to_val)
|
||||
{
|
||||
if (to_val)
|
||||
AddEffect("NoPowerNeed", this, 1);
|
||||
else
|
||||
RemoveEffect("NoPowerNeed", this);
|
||||
return true;
|
||||
}
|
||||
|
||||
public func FxNoPowerNeedSaveScen(object obj, proplist fx, proplist props)
|
||||
{
|
||||
// This building doesn't need power, save that to scenario.
|
||||
props->AddCall("NoPowerNeed", obj, "SetNoPowerNeed", true);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Wrapper for MakePowerConsumer to handle requesting 0 power and the NoPowerNeed rule correctly.
|
||||
// With an option to just pass on to the global method.
|
||||
public func MakePowerConsumer(int amount, bool just_pass_to_global)
|
||||
{
|
||||
if (just_pass_to_global == true)
|
||||
return inherited(amount, just_pass_to_global, ...);
|
||||
|
||||
var no_power_need = !!ObjectCount(Find_ID(Rule_NoPowerNeed)) || GetEffect("NoPowerNeed", this);
|
||||
|
||||
// Don't do anything if the request is the exact same as the previous one (succesive call).
|
||||
if ((amount > 0) && !no_power_need)
|
||||
if (last_request == PowerConsumer_LPR_NonZero)
|
||||
if (last_amount == amount)
|
||||
return true;
|
||||
|
||||
// Special handling for zero amount.
|
||||
if ((amount == 0) || no_power_need)
|
||||
{
|
||||
// Initially requesting 0 power?
|
||||
if (last_request == PowerConsumer_LPR_None)
|
||||
{
|
||||
last_request = PowerConsumer_LPR_Zero;
|
||||
last_amount = amount;
|
||||
// Always enable.
|
||||
this->~OnEnoughPower();
|
||||
return true;
|
||||
}
|
||||
// Requesting 0 power as a second request.
|
||||
else if (last_request == PowerConsumer_LPR_Zero)
|
||||
{
|
||||
last_amount = amount;
|
||||
// Should still have power at this point.
|
||||
return true;
|
||||
}
|
||||
// Requesting 0 power after having requested nonzero power.
|
||||
else
|
||||
{
|
||||
last_request = PowerConsumer_LPR_Zero;
|
||||
last_amount = amount;
|
||||
// Remove as official power consumer.
|
||||
inherited(0);
|
||||
// Re-enable power supply.
|
||||
this->~OnEnoughPower();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Requesting power != 0.
|
||||
last_request = PowerConsumer_LPR_NonZero;
|
||||
last_amount = amount;
|
||||
}
|
||||
|
||||
return inherited(amount, just_pass_to_global, ...);
|
||||
}
|
||||
|
||||
// Turns the object off as a power consumer.
|
||||
public func UnmakePowerConsumer()
|
||||
{
|
||||
// Succesive calls have no effect.
|
||||
if (last_request == PowerConsumer_LPR_None)
|
||||
return true;
|
||||
|
||||
// We don't have power anymore.
|
||||
has_power = false;
|
||||
|
||||
// We were not officially registered as power consumer anyway.
|
||||
if (last_request == PowerConsumer_LPR_Zero)
|
||||
{
|
||||
last_request = PowerConsumer_LPR_None;
|
||||
return true;
|
||||
}
|
||||
last_request = PowerConsumer_LPR_None;
|
||||
return MakePowerConsumer(0, true);
|
||||
}
|
||||
|
||||
// Destruction callback: let power network know this object is not a consumer anymore.
|
||||
// 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.
|
||||
public func Destruction()
|
||||
{
|
||||
UnmakePowerConsumer();
|
||||
UnregisterPowerRequest();
|
||||
return _inherited(...);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
[DefCore]
|
||||
id=Library_Power
|
||||
Version=6,0
|
||||
Category=C4D_StaticBack
|
||||
Width=1
|
||||
Height=1
|
||||
Offset=-1,-1
|
||||
Category=C4D_StaticBack
|
|
@ -1,29 +1,100 @@
|
|||
/**
|
||||
Power Producer
|
||||
Handles some aspects of power producing structures, this library should be
|
||||
included by all power producing structures. These structures can overload
|
||||
the function GetProducerPriority() and return the priority for delivering
|
||||
power to the network. The library will preferentially drain power from the
|
||||
producers with highest priority, so that on-demand producers are not drained
|
||||
before power storages or steady producers. Typical return values are:
|
||||
included by all power producing structures. Certain functions should be
|
||||
overloaded and others can be used to implement the production of power
|
||||
in a uniform way consistent with the network, see text below.
|
||||
|
||||
The interface is built up such that the producer can let the network know it
|
||||
is ready to deliver power to the network by the functions
|
||||
* RegisterPowerProduction(int amount)
|
||||
* UnregisterPowerProduction()
|
||||
Then the network will address the power producer via the callbacks
|
||||
* OnPowerProductionStart(int amount)
|
||||
* OnPowerProductionStop()
|
||||
to start and stop the power production. The producer should overload these
|
||||
functions and return true if the starting or stopping has succeeded. For
|
||||
steady producers these calls are not made and a steady production of power
|
||||
is assumed. A steady producer should have return value true for the function
|
||||
* IsSteadyPowerProducer()
|
||||
|
||||
These structures can overload the function GetProducerPriority() and return
|
||||
the priority for delivering power to the network. The library will
|
||||
preferentially drain power from the producers with highest priority, so that
|
||||
on-demand producers are not drained before power storages or steady producers.
|
||||
Typical return values are:
|
||||
* Wind generator: 100
|
||||
* Compensator: 50
|
||||
* Steam engine: 0
|
||||
* Steam engine: 0
|
||||
See also the scripts of these structures for more details on the usage of the
|
||||
power producer library.
|
||||
|
||||
Note that the object including this library should return _inherited(...) in
|
||||
the Destruction callback if overloaded.
|
||||
|
||||
@author Zapper, Maikel
|
||||
*/
|
||||
|
||||
|
||||
// This object is a power producer.
|
||||
public func IsPowerProducer() { return true; }
|
||||
|
||||
|
||||
/*-- Interface -- */
|
||||
|
||||
// Call this function in the power producing structure to indicate to the network
|
||||
// that this structure is available and able to produce the specified amount of power.
|
||||
private func RegisterPowerProduction(int amount)
|
||||
{
|
||||
Library_Power->RegisterPowerProducer(this, amount);
|
||||
return;
|
||||
}
|
||||
|
||||
// Call this function in the power producing structure to indicate to the network
|
||||
// that this structure is not able to produce any power any more.
|
||||
private func UnregisterPowerProduction()
|
||||
{
|
||||
Library_Power->UnregisterPowerProducer(this);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*-- Callbacks --*/
|
||||
|
||||
// Callback by the power network. Overload this function and start the production
|
||||
// of power in this structure for the requested amount if possible.
|
||||
public func OnPowerProductionStart(int amount)
|
||||
{
|
||||
// A return value of false indicates to the network that power production is not possible.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Callback by the power network. Overload this function and stop the production
|
||||
// of power in this structure if possible.
|
||||
public func OnPowerProductionStop()
|
||||
{
|
||||
// A return value of false indicates to the network that stopping the current production
|
||||
// was not possible, this should in principle never happen. However, if so the network
|
||||
// must assume this producer is still actively delivering power.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Whether this object is a steady power producer which continuously delivers
|
||||
// power to the network it is in, a producer is not steady by default.
|
||||
public func IsSteadyPowerProducer() { return false; }
|
||||
|
||||
// Producer priority: the willingsness of a producer to deliver energy.
|
||||
// This is high for steady producers like the wind generator and low
|
||||
// for producers like the steam engine.
|
||||
public func GetProducerPriority() { return 0; }
|
||||
|
||||
// Destruction callback: let power network know this object is not a producer anymore.
|
||||
|
||||
/*-- Library Code --*/
|
||||
|
||||
// Destruction callback by the engine: let power network know this object is not a producer
|
||||
// anymore. A power producer must always be unregistered from the network.
|
||||
public func Destruction()
|
||||
{
|
||||
MakePowerProducer(0);
|
||||
UnregisterPowerProduction();
|
||||
return _inherited(...);
|
||||
}
|
||||
|
|
|
@ -1,312 +1,148 @@
|
|||
/**
|
||||
Power Library
|
||||
Cares about power management of a base.
|
||||
Handles the aspects for a single power networks, for each network in a round
|
||||
a copy of this library object is created. For each network it is being kept
|
||||
track of which are the idle/active producers and idle/active consumers and
|
||||
power is requested from producers and distributed for consumers according
|
||||
to priority.
|
||||
|
||||
callbacks:
|
||||
QueryWaivePowerRequest()
|
||||
OnNotEnoughPower()
|
||||
OnEnoughPower()
|
||||
OnRemovedFromPowerSleepingQueue(): called when the object was removed from the sleeping queue
|
||||
|
||||
globals:
|
||||
MakePowerConsumer(int amount)
|
||||
Note: power consumers include the library Library_PowerConsumer and should use UnmakePowerConsumer to turn off as power consumers
|
||||
MakePowerProducer(int amount)
|
||||
IsPowerAvailable(int amount)
|
||||
Callbacks to the power producers (see producer library for details):
|
||||
* OnPowerProductionStart(int amount)
|
||||
* OnPowerProductionStop()
|
||||
* GetProducerPriority()
|
||||
* IsSteadyPowerProducer()
|
||||
|
||||
Callbacks to the power consumers (see consumer library for details):
|
||||
* OnEnoughPower(int amount)
|
||||
* OnNotEnoughPower()
|
||||
* GetConsumerPriority()
|
||||
* GetActualPowerConsumer()
|
||||
|
||||
The network object keeps track of the producers and consumers in lists.
|
||||
* lib_idle_producers (currently not producing power)
|
||||
* lib_active_producers (currently producing power)
|
||||
* lib_waiting_consumers (waiting for power)
|
||||
* lib_active_consumers (supplied consumers)
|
||||
Producers are stored according to {obj, prod_amount, priority} and consumers
|
||||
according to {obj, cons_amount, priority}.
|
||||
|
||||
OPEN TODOS:
|
||||
* Figure out where the nil's and the errors come from.
|
||||
* Implement correct treatment for steady producers.
|
||||
* Check the flag library for network merging.
|
||||
* Check the power balance, also with merging.
|
||||
|
||||
@author Zapper, Maikel
|
||||
*/
|
||||
|
||||
static Library_Power_power_compounds;
|
||||
|
||||
// for the helper definitions
|
||||
local power_links; // producers and consumers
|
||||
local sleeping_links;
|
||||
local power_balance; // performance
|
||||
local neutral; // is "the" neutral helper?
|
||||
// A static variable is used to store the different power networks.
|
||||
// This variable is also accessed by the flag library.
|
||||
static LIB_POWR_Networks;
|
||||
|
||||
// Lists to keep track of the producers and consumers.
|
||||
local lib_idle_producers;
|
||||
local lib_active_producers;
|
||||
local lib_waiting_consumers;
|
||||
local lib_active_consumers;
|
||||
|
||||
// Main variable which keeps track of the power balance in the network.
|
||||
local lib_power_balance;
|
||||
|
||||
// Whether the network is neutral.
|
||||
local lib_neutral_network;
|
||||
|
||||
// Initialize the local variables needed to keep track of each power network.
|
||||
protected func Initialize()
|
||||
{
|
||||
power_links = [];
|
||||
sleeping_links = [];
|
||||
power_balance = 0;
|
||||
neutral = false;
|
||||
// Initialize producer and consumer lists.
|
||||
lib_idle_producers = [];
|
||||
lib_active_producers = [];
|
||||
lib_waiting_consumers = [];
|
||||
lib_active_consumers = [];
|
||||
// Set power balance to zero.
|
||||
lib_power_balance = 0;
|
||||
// Network is not neutral by default.
|
||||
lib_neutral_network = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Adds a power consumer to the network which produces an amount of power.
|
||||
public func AddPowerProducer(object producer, int amount)
|
||||
|
||||
/*-- Definition Calls --*/
|
||||
|
||||
// Definition call: registers a power producer with specified amount.
|
||||
public func RegisterPowerProducer(object producer, int amount)
|
||||
{
|
||||
return AddPowerLink(producer, amount);
|
||||
// Definition call safety checks.
|
||||
if (this != Library_Power || !producer || !producer->~IsPowerProducer())
|
||||
return FatalError("RegisterPowerProducer() either not called from definition context or no producer specified.");
|
||||
Library_Power->Init();
|
||||
// Find the network for this producer and add it.
|
||||
var network = GetPowerNetwork(producer);
|
||||
network->AddPowerProducer(producer, amount, producer->GetProducerPriority());
|
||||
return;
|
||||
}
|
||||
|
||||
// Adds a power consumer to the network which consumes an amount of power.
|
||||
public func AddPowerConsumer(object consumer, int amount)
|
||||
// Definition call: unregisters a power producer.
|
||||
public func UnregisterPowerProducer(object producer)
|
||||
{
|
||||
// Check whether this consumer is among the sleeping links of this network.
|
||||
for (var i = GetLength(sleeping_links) - 1; i >= 0; i--)
|
||||
{
|
||||
var link = sleeping_links[i];
|
||||
if (link.obj != consumer)
|
||||
continue;
|
||||
// Did not affect power balance, we can just remove/change the link.
|
||||
// If amount equals zero, we can remove the consumer from the network.
|
||||
if (amount == 0)
|
||||
{
|
||||
sleeping_links[i] = sleeping_links[GetLength(sleeping_links) - 1];
|
||||
SetLength(sleeping_links, GetLength(sleeping_links) - 1);
|
||||
// Visualize the consumption change and notify the link object.
|
||||
VisualizePowerChange(link.obj, 0, link.amount, false);
|
||||
link.obj->~OnRemovedFromPowerSleepingQueue();
|
||||
return true;
|
||||
}
|
||||
// Otherwise, set the new power consumption of this link.
|
||||
sleeping_links[i].amount = -amount;
|
||||
return true;
|
||||
}
|
||||
// Consumer is not a sleeping link, therefore add it to the network.
|
||||
return AddPowerLink(consumer, -amount);
|
||||
// Definition call safety checks.
|
||||
if (this != Library_Power || !producer || !producer->~IsPowerProducer())
|
||||
return FatalError("UnregisterPowerProducer() either not called from definition context or no producer specified.");
|
||||
Library_Power->Init();
|
||||
// Find the network for this producer and remove it.
|
||||
var network = GetPowerNetwork(producer);
|
||||
network->RemovePowerProducer(producer);
|
||||
return;
|
||||
}
|
||||
|
||||
// Removes a power link from its network.
|
||||
public func RemovePowerLink(object power_link)
|
||||
// Definition call: registers a power consumer with specified amount.
|
||||
public func RegisterPowerConsumer(object consumer, int amount)
|
||||
{
|
||||
return AddPowerLink(power_link, 0);
|
||||
// Definition call safety checks.
|
||||
if (this != Library_Power || !consumer || !consumer->~IsPowerConsumer())
|
||||
return FatalError("RegisterPowerConsumer() either not called from definition context or no consumer specified.");
|
||||
Library_Power->Init();
|
||||
// Find the network for this consumer and add it.
|
||||
var network = GetPowerNetwork(consumer);
|
||||
network->AddPowerConsumer(consumer, amount, consumer->GetConsumerPriority());
|
||||
return;
|
||||
}
|
||||
|
||||
// Adds a power link to the network.
|
||||
public func AddPowerLink(object power_link, int power_amount, bool surpress_balance_check)
|
||||
// Definition call: unregisters a power consumer.
|
||||
public func UnregisterPowerConsumer(object consumer)
|
||||
{
|
||||
var new_link = {obj = power_link, amount = power_amount};
|
||||
|
||||
var before = 0;
|
||||
var found = false;
|
||||
var first_empty = -1;
|
||||
var diff = 0;
|
||||
for (var i = GetLength(power_links) - 1; i >= 0; i--)
|
||||
{
|
||||
var link = power_links[i];
|
||||
// Possible
|
||||
if (link == nil)
|
||||
{
|
||||
first_empty = i;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Removed from outside.
|
||||
if (link.obj == nil)
|
||||
{
|
||||
power_links[i] = nil;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (link.obj != power_link)
|
||||
continue;
|
||||
found = true;
|
||||
|
||||
diff = power_amount - link.amount;
|
||||
power_balance += diff;
|
||||
before = power_links[i].amount;
|
||||
|
||||
if (power_amount == 0)
|
||||
power_links[i] = nil;
|
||||
else
|
||||
power_links[i] = new_link;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
// place to insert?
|
||||
if (power_amount != 0)
|
||||
{
|
||||
if (first_empty != -1)
|
||||
power_links[first_empty] = new_link;
|
||||
else
|
||||
power_links[GetLength(power_links)] = new_link;
|
||||
}
|
||||
diff = new_link.amount;
|
||||
power_balance += diff;
|
||||
}
|
||||
|
||||
if ((new_link.amount > 0) || ((new_link.amount == 0) && (before > 0)))
|
||||
VisualizePowerChange(new_link.obj, new_link.amount, before, false);
|
||||
else if ((new_link.amount < 0) || ((new_link.amount == 0) && (before < 0)))
|
||||
VisualizePowerChange(new_link.obj, new_link.amount, before, false);
|
||||
if (new_link.amount < 0)
|
||||
new_link.obj->~OnEnoughPower(); // might be reverted soon, though
|
||||
|
||||
if (!surpress_balance_check)
|
||||
CheckPowerBalance();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Main function of the power library which checks the power balance in a closed network.
|
||||
// This function will deactivate consumers and activate producers whenever necessary.
|
||||
public func CheckPowerBalance()
|
||||
{
|
||||
// Special handling for ownerless links: always sleep them.
|
||||
if (neutral)
|
||||
{
|
||||
for (var i = GetLength(power_links) - 1; i >= 0; i--)
|
||||
{
|
||||
var link = power_links[i];
|
||||
if (link == nil)
|
||||
continue;
|
||||
// Power producers don't need te be put down.
|
||||
if (link.amount > 0)
|
||||
continue;
|
||||
SleepLink(i);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Network is not neutral so we can revive sleeping links if the balance is positive.
|
||||
if (power_balance >= 0)
|
||||
{
|
||||
// Loop over all sleeping links and find the best one to revive.
|
||||
// This is the link with highest priority and which fits the power surplus.
|
||||
var highest_priority = -0xffffff;
|
||||
var best_link = nil;
|
||||
for (var i = GetLength(sleeping_links) - 1; i >= 0; i--)
|
||||
{
|
||||
var link = sleeping_links[i];
|
||||
if (link.obj == nil)
|
||||
{
|
||||
sleeping_links[i] = sleeping_links[GetLength(sleeping_links) - 1];
|
||||
SetLength(sleeping_links, GetLength(sleeping_links) - 1);
|
||||
continue;
|
||||
}
|
||||
// Check if there is enough power to revive this link.
|
||||
if (power_balance + link.amount < 0)
|
||||
continue;
|
||||
// Store the link with current highest priority.
|
||||
var priority = link.obj->~GetConsumerPriority();
|
||||
if (priority > highest_priority)
|
||||
{
|
||||
highest_priority = priority;
|
||||
best_link = i;
|
||||
}
|
||||
}
|
||||
// Revive the best link if found and don't execute the rest of this function.
|
||||
if (best_link != nil)
|
||||
UnsleepLink(best_link);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Network has not enough available power: we need to deactivate some consumers.
|
||||
// Look for the best link to sleep.
|
||||
var best_amount = -0xffffff;
|
||||
var least_priority = 0xffffff;
|
||||
var best_link = nil;
|
||||
for (var i = GetLength(power_links) - 1; i >= 0; i--)
|
||||
{
|
||||
var link = power_links[i];
|
||||
// Do not shut down producers or invalid links.
|
||||
if (link == nil || link.amount > 0)
|
||||
continue;
|
||||
// New best link if priority is less or equal and amount is larger.
|
||||
var amount = -link.amount;
|
||||
var priority = link.obj->~GetConsumerPriority();
|
||||
if (priority < least_priority || (priority == least_priority && amount > best_amount))
|
||||
{
|
||||
best_amount = amount;
|
||||
least_priority = priority;
|
||||
best_link = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Total blackout? No consumer active anymore?
|
||||
if (best_link == nil)
|
||||
return false;
|
||||
|
||||
// There is a link which we can sleep.
|
||||
SleepLink(best_link);
|
||||
|
||||
// Recurse, because we might need to sleep another link or might activate a consumer with less demands.
|
||||
CheckPowerBalance();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Removes a link with given index from the power links and adds it to the sleeping links.
|
||||
public func SleepLink(int index)
|
||||
{
|
||||
// Safety: index must be valid.
|
||||
if (index < 0 || index >= GetLength(power_links))
|
||||
return FatalError("SleepLink() called without or invalid index!");
|
||||
// Only sleep consumers, it does not make sense to sleep producers.
|
||||
var link = power_links[index];
|
||||
if (link.amount > 0)
|
||||
return FatalError("SleepLink() trying to sleep a producer!");
|
||||
// Delete link from power links and add to sleeping links.
|
||||
power_links[index] = nil;
|
||||
power_balance -= link.amount;
|
||||
sleeping_links[GetLength(sleeping_links)] = link;
|
||||
// Notify link that it has not enough power and visualize the change.
|
||||
link.obj->~OnNotEnoughPower();
|
||||
VisualizePowerChange(link.obj, 0, link.amount, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Removes a link with given index from the sleeping links and adds it to the power links.
|
||||
public func UnsleepLink(int index)
|
||||
{
|
||||
// Safety: index must be valid.
|
||||
if (index < 0 || index >= GetLength(sleeping_links))
|
||||
return FatalError("UnsleepLink() called without or invalid index!");
|
||||
// Get the sleeping link.
|
||||
var link = sleeping_links[index];
|
||||
// Delete this link from the list of sleeping links.
|
||||
sleeping_links[index] = sleeping_links[GetLength(sleeping_links) - 1];
|
||||
SetLength(sleeping_links, GetLength(sleeping_links) - 1);
|
||||
// Revive the link by adding it to the power links.
|
||||
return AddPowerLink(link.obj, link.amount);
|
||||
}
|
||||
|
||||
// get requested power of nodes that are currently sleeping
|
||||
public func GetPendingPowerAmount()
|
||||
{
|
||||
var sum = 0;
|
||||
for (var i = GetLength(sleeping_links) - 1; i >= 0; i--)
|
||||
sum += -sleeping_links[i].amount;
|
||||
return sum;
|
||||
}
|
||||
|
||||
// should always be above zero - otherwise an object would have been deactivated
|
||||
public func GetPowerBalance()
|
||||
{
|
||||
return power_balance;
|
||||
}
|
||||
|
||||
public func IsPowerAvailable(object obj, int amount)
|
||||
{
|
||||
// Ignore object for now.
|
||||
return power_balance >= amount;
|
||||
}
|
||||
|
||||
public func Init()
|
||||
{
|
||||
if (GetType(Library_Power_power_compounds) != C4V_Array)
|
||||
Library_Power_power_compounds = [];
|
||||
// Definition call safety checks.
|
||||
if (this != Library_Power || !consumer || !consumer->~IsPowerConsumer())
|
||||
return FatalError("UnregisterPowerConsumer() either not called from definition context or no consumer specified.");
|
||||
Library_Power->Init();
|
||||
// Find the network for this consumer and remove it.
|
||||
var network = GetPowerNetwork(consumer);
|
||||
network->RemovePowerConsumer(consumer);
|
||||
return;
|
||||
}
|
||||
|
||||
// Definition call: gives the power helper object.
|
||||
public func GetPowerHelperForObject(object who)
|
||||
// TODO: Clean up this code!
|
||||
public func GetPowerNetwork(object for_obj)
|
||||
{
|
||||
// Definition call safety checks.
|
||||
if (this != Library_Power || !for_obj)
|
||||
return FatalError("GetPowerNetwork() either not called from definition context or no object specified.");
|
||||
|
||||
var w;
|
||||
while(w = who->~GetActualPowerConsumer())
|
||||
while (w = for_obj->~GetActualPowerConsumer())
|
||||
{
|
||||
if (w == who)
|
||||
if (w == for_obj)
|
||||
break; // nope
|
||||
who = w;
|
||||
for_obj = w;
|
||||
}
|
||||
var flag = GetFlagpoleForPosition(who->GetX() - GetX(), who->GetY() - GetY());
|
||||
var flag = GetFlagpoleForPosition(for_obj->GetX() - GetX(), for_obj->GetY() - GetY());
|
||||
|
||||
var helper = nil;
|
||||
if (!flag) // neutral - needs neutral helper
|
||||
{
|
||||
for (var obj in Library_Power_power_compounds)
|
||||
for (var obj in LIB_POWR_Networks)
|
||||
{
|
||||
if (!obj || !obj.neutral)
|
||||
continue;
|
||||
|
@ -318,7 +154,7 @@ public func GetPowerHelperForObject(object who)
|
|||
{
|
||||
helper = CreateObjectAbove(Library_Power, 0, 0, NO_OWNER);
|
||||
helper.neutral = true;
|
||||
Library_Power_power_compounds[GetLength(Library_Power_power_compounds)] = helper;
|
||||
LIB_POWR_Networks[GetLength(LIB_POWR_Networks)] = helper;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -327,8 +163,8 @@ public func GetPowerHelperForObject(object who)
|
|||
|
||||
if (helper == nil)
|
||||
{
|
||||
helper = CreateObjectAbove(Library_Power, 0, 0, NO_OWNER);
|
||||
Library_Power_power_compounds[GetLength(Library_Power_power_compounds)] = helper;
|
||||
helper = CreateObject(Library_Power, 0, 0, NO_OWNER);
|
||||
LIB_POWR_Networks[GetLength(LIB_POWR_Networks)] = helper;
|
||||
|
||||
// Add to all linked flags.
|
||||
flag->SetPowerHelper(helper);
|
||||
|
@ -344,71 +180,354 @@ public func GetPowerHelperForObject(object who)
|
|||
return helper;
|
||||
}
|
||||
|
||||
|
||||
/*-- Global Interface --*/
|
||||
|
||||
// Returns the amount of unavailable power that is currently being requested.
|
||||
global func GetPendingPowerAmount()
|
||||
// Definition call: Initializes tracking of the power networks.
|
||||
public func Init()
|
||||
{
|
||||
if (!this)
|
||||
return 0;
|
||||
Library_Power->Init();
|
||||
return (Library_Power->GetPowerHelperForObject(this))->GetPendingPowerAmount();
|
||||
}
|
||||
|
||||
// Returns the current power balance of the area an object is in.
|
||||
// This is roughly equivalent to produced power - consumed power.
|
||||
global func GetCurrentPowerBalance()
|
||||
{
|
||||
if (!this)
|
||||
return 0;
|
||||
Library_Power->Init();
|
||||
return (Library_Power->GetPowerHelperForObject(this))->GetPowerBalance();
|
||||
}
|
||||
|
||||
// Turns the object into a power producer that produces amount of power until this function is called again with amount = 0.
|
||||
global func MakePowerProducer(int amount)
|
||||
{
|
||||
if (!this)
|
||||
return false;
|
||||
Library_Power->Init();
|
||||
var power_helper = Library_Power->GetPowerHelperForObject(this);
|
||||
if (!power_helper)
|
||||
return false;
|
||||
return power_helper->AddPowerProducer(this, amount);
|
||||
}
|
||||
|
||||
// Turns the power producer into an object that does not produce power.
|
||||
global func UnmakePowerProducer()
|
||||
{
|
||||
MakePowerProducer(0);
|
||||
// Definition call safety checks.
|
||||
if (this != Library_Power)
|
||||
return;
|
||||
// Initialize the list of networks if not done already.
|
||||
if (GetType(LIB_POWR_Networks) != C4V_Array)
|
||||
LIB_POWR_Networks = [];
|
||||
return;
|
||||
}
|
||||
|
||||
// Returns true if the current power balance is bigger or equal to the requested amount.
|
||||
global func IsPowerAvailable(int amount)
|
||||
|
||||
/*-- Library Code --*/
|
||||
|
||||
public func AddPowerProducer(object producer, int amount, int prio)
|
||||
{
|
||||
if (!this)
|
||||
return false;
|
||||
Library_Power->Init();
|
||||
return (Library_Power->GetPowerHelperForObject(this))->IsPowerAvailable(this, amount);
|
||||
// Debugging logs.
|
||||
Log("POWR - AddPowerProducer(): network = %v, frame = %d, producer = %v, amount = %d, priority = %d", this, FrameCounter(), producer, amount, prio);
|
||||
// Check if it is not already in the list of idle producers.
|
||||
for (var index = GetLength(lib_idle_producers) - 1; index >= 0; index--)
|
||||
{
|
||||
var link = lib_idle_producers[index];
|
||||
if (!link || link.obj != producer)
|
||||
continue;
|
||||
// If it is in the list update the values if they have changed.
|
||||
if (link.prod_amount != amount || link.priority != prio)
|
||||
{
|
||||
lib_idle_producers[index] = {obj = producer, prod_amount = amount, priority = prio};
|
||||
// Check the power balance of this network, since a change has been made.
|
||||
CheckPowerBalance();
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Check if it is not already in the list of active producers.
|
||||
for (var index = GetLength(lib_active_producers) - 1; index >= 0; index--)
|
||||
{
|
||||
var link = lib_active_producers[index];
|
||||
if (!link || link.obj != producer)
|
||||
continue;
|
||||
// If it is in the list update the values if they have changed.
|
||||
if (link.prod_amount != amount || link.priority != prio)
|
||||
{
|
||||
lib_active_producers[index] = {obj = producer, prod_amount = amount, priority = prio};
|
||||
// Check the power balance of this network, since a change has been made.
|
||||
CheckPowerBalance();
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Producer was in neither list, so add it to the list of idle producers.
|
||||
PushBack(lib_idle_producers, {obj = producer, prod_amount = amount, priority = prio});
|
||||
// Check the power balance of this network, since a change has been made.
|
||||
CheckPowerBalance();
|
||||
return;
|
||||
}
|
||||
|
||||
// Turns the object into a power consumer, consumption is turned of with amoun = 0.
|
||||
global func MakePowerConsumer(int amount)
|
||||
public func RemovePowerProducer(object producer)
|
||||
{
|
||||
if (!this)
|
||||
return false;
|
||||
Library_Power->Init();
|
||||
return (Library_Power->GetPowerHelperForObject(this))->AddPowerConsumer(this, amount);
|
||||
// Debugging logs.
|
||||
Log("POWR - RemovePowerProducer(): network = %v, frame = %d, producer = %v", this, FrameCounter(), producer);
|
||||
// Remove producer from the list of idle producers if it is in there.
|
||||
for (var index = GetLength(lib_idle_producers) - 1; index >= 0; index--)
|
||||
{
|
||||
var link = lib_idle_producers[index];
|
||||
if (!link || link.obj != producer)
|
||||
continue;
|
||||
// Remove the producer from the list.
|
||||
RemoveArrayIndex(lib_idle_producers, index);
|
||||
return;
|
||||
}
|
||||
// Otherwise, remove producer from the list of active producers if it is in there.
|
||||
for (var index = GetLength(lib_active_producers) - 1; index >= 0; index--)
|
||||
{
|
||||
var link = lib_active_producers[index];
|
||||
if (!link || link.obj != producer)
|
||||
continue;
|
||||
// Reduce the power balance and remove the producer from the list.
|
||||
lib_power_balance -= link.prod_amount;
|
||||
RemoveArrayIndex(lib_active_producers, index);
|
||||
// Notify the active power producer that it should stop producing power.
|
||||
producer->OnPowerProductionStop();
|
||||
// Check the power balance of this network, since a change has been made.
|
||||
CheckPowerBalance();
|
||||
VisualizePowerChange(link.obj, link.prod_amount, 0, false);
|
||||
return;
|
||||
}
|
||||
// If found in neither lists just return without doing anything.
|
||||
return;
|
||||
}
|
||||
|
||||
public func AddPowerConsumer(object consumer, int amount, int prio)
|
||||
{
|
||||
// Debugging logs.
|
||||
Log("POWR - AddPowerConsumer(): network = %v, frame = %d, consumer = %v, amount = %d, priority = %d", this, FrameCounter(), consumer, amount, prio);
|
||||
// Check if it is not already in the list of waiting consumers.
|
||||
for (var index = GetLength(lib_waiting_consumers) - 1; index >= 0; index--)
|
||||
{
|
||||
var link = lib_waiting_consumers[index];
|
||||
if (!link || link.obj != consumer)
|
||||
continue;
|
||||
// If it is in the list update the values if they have changed.
|
||||
if (link.cons_amount != amount || link.priority != prio)
|
||||
{
|
||||
lib_waiting_consumers[index] = {obj = consumer, cons_amount = amount, priority = prio};
|
||||
// Check the power balance of this network, since a change has been made.
|
||||
CheckPowerBalance();
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Check if it is not already in the list of active consumers.
|
||||
for (var index = GetLength(lib_active_consumers) - 1; index >= 0; index--)
|
||||
{
|
||||
var link = lib_active_consumers[index];
|
||||
if (!link || link.obj != consumer)
|
||||
continue;
|
||||
// If it is in the list update the values if they have changed.
|
||||
if (link.cons_amount != amount || link.priority != prio)
|
||||
{
|
||||
lib_active_consumers[index] = {obj = consumer, cons_amount = amount, priority = prio};
|
||||
// Check the power balance of this network, since a change has been made.
|
||||
CheckPowerBalance();
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Consumer was in neither list, so add it to the list of waiting consumers.
|
||||
PushBack(lib_waiting_consumers, {obj = consumer, cons_amount = amount, priority = prio});
|
||||
// Check the power balance of this network, since a change has been made.
|
||||
CheckPowerBalance();
|
||||
return;
|
||||
}
|
||||
|
||||
public func RemovePowerConsumer(object consumer)
|
||||
{
|
||||
// Debugging logs.
|
||||
Log("POWR - RemovePowerConsumer(): network = %v, frame = %d, consumer = %v", this, FrameCounter(), consumer);
|
||||
// Remove consumer from the list of waiting consumers if it is in there.
|
||||
for (var index = GetLength(lib_waiting_consumers) - 1; index >= 0; index--)
|
||||
{
|
||||
var link = lib_waiting_consumers[index];
|
||||
if (!link || link.obj != consumer)
|
||||
continue;
|
||||
// Remove the consumer from the list.
|
||||
RemoveArrayIndex(lib_waiting_consumers, index);
|
||||
return;
|
||||
}
|
||||
// Otherwise, remove consumer from the list of active consumers if it is in there.
|
||||
for (var index = GetLength(lib_active_consumers) - 1; index >= 0; index--)
|
||||
{
|
||||
var link = lib_active_consumers[index];
|
||||
if (!link || link.obj != consumer)
|
||||
continue;
|
||||
// Increase the power balance and remove the consumer from the list.
|
||||
lib_power_balance += link.cons_amount;
|
||||
RemoveArrayIndex(lib_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);
|
||||
return;
|
||||
}
|
||||
// If found in neither lists just return without doing anything.
|
||||
return;
|
||||
}
|
||||
|
||||
private func CheckPowerBalance()
|
||||
{
|
||||
// First get the possible power surplus in the network from idle producers.
|
||||
var surplus = GetPowerSurplus();
|
||||
|
||||
// Debugging logs.
|
||||
LogState("balance start");
|
||||
|
||||
// If the surplus is non-positive it implies that first all possible idle producers
|
||||
// need to be activated and then some consumers need to be deactivated.
|
||||
if (surplus <= 0 && lib_power_balance < 0)
|
||||
{
|
||||
// Activate all idle producers.
|
||||
ActivateProducers(surplus - lib_power_balance);
|
||||
// The power balance may have changed but can't be positive, so disable sufficient consumers.
|
||||
DeactivateConsumers(-lib_power_balance);
|
||||
// All producers are running and the maximum amount of consumers as well.
|
||||
LogState("balance_end s < 0");
|
||||
return;
|
||||
}
|
||||
// Otherwise if the surplus is positive one or some idle consumers may be activated.
|
||||
else if (surplus > 0)
|
||||
{
|
||||
// Activate waiting consumers according to the surplus and their priorities.
|
||||
ActivateConsumers(surplus);
|
||||
// These newly activated consumers and the already maybe negative power balance must then
|
||||
// finally be counteracted by activating idle producers according to the new balance.
|
||||
// It is also possible that some producers may be deactivated.
|
||||
if (lib_power_balance > 0)
|
||||
DeactivateProducers(lib_power_balance);
|
||||
else if (lib_power_balance < 0)
|
||||
ActivateProducers(-lib_power_balance);
|
||||
LogState("balance_end s > 0");
|
||||
return;
|
||||
}
|
||||
// TODO: what about the third case? Should we really do nothing there?
|
||||
// TODO: what about swapping consumers with different priority?
|
||||
LogState("balance_end s == 0");
|
||||
return;
|
||||
}
|
||||
|
||||
// Returns the possible power production from idle producers combined with the current power balance.
|
||||
private func GetPowerSurplus()
|
||||
{
|
||||
// This is just the sum of the balance and possible power from all idle producers.
|
||||
var surplus = lib_power_balance;
|
||||
for (var index = GetLength(lib_idle_producers) - 1; index >= 0; index--)
|
||||
{
|
||||
var link = lib_idle_producers[index];
|
||||
if (!link)
|
||||
continue;
|
||||
surplus += link.prod_amount;
|
||||
}
|
||||
return surplus;
|
||||
}
|
||||
|
||||
// Activates idle producers according to priority until power need is satisfied.
|
||||
private func ActivateProducers(int power_need)
|
||||
{
|
||||
// Debugging logs.
|
||||
Log("POWR - ActivateProducers(): network = %v, frame = %d, power_need = %d", this, FrameCounter(), power_need);
|
||||
var power_found = 0;
|
||||
// Sort the idle producers according to priority and then activate producers until balance is restored.
|
||||
if (GetLength(lib_idle_producers) > 1) SortArrayByProperty(lib_idle_producers, "priority");
|
||||
for (var index = GetLength(lib_idle_producers) - 1; index >= 0; index--)
|
||||
{
|
||||
var link = lib_idle_producers[index];
|
||||
if (!link)
|
||||
continue;
|
||||
power_found += link.prod_amount;
|
||||
PushBack(lib_active_producers, link);
|
||||
link.obj->OnPowerProductionStart(link.prod_amount);
|
||||
lib_power_balance += link.prod_amount;
|
||||
SetLength(lib_idle_producers, index);
|
||||
VisualizePowerChange(link.obj, 0, link.prod_amount, false);
|
||||
// Stop activatng producers if power need is satisfied.
|
||||
if (power_found >= power_need)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Deactivates idle producers according to priority until power surplus is gone.
|
||||
private func DeactivateProducers(int power_surplus)
|
||||
{
|
||||
// Debugging logs.
|
||||
Log("POWR - DeactivateProducers(): network = %v, frame = %d, power_surplus = %d", this, FrameCounter(), power_surplus);
|
||||
var power_killed = 0;
|
||||
// Sort the active producers according to priority and deactivate them until balance is restored.
|
||||
if (GetLength(lib_active_producers) > 1) SortArrayByProperty(lib_active_producers, "priority", true);
|
||||
for (var index = GetLength(lib_active_producers) - 1; index >= 0; index--)
|
||||
{
|
||||
var link = lib_active_producers[index];
|
||||
power_killed += link.prod_amount;
|
||||
// Stop deactivating producers if power surplus has been reached.
|
||||
if (power_killed > power_surplus)
|
||||
break;
|
||||
// Move active producer to idle producers.
|
||||
PushBack(lib_idle_producers, link);
|
||||
link.obj->OnPowerProductionStop();
|
||||
lib_power_balance -= link.prod_amount;
|
||||
SetLength(lib_active_producers, index);
|
||||
VisualizePowerChange(link.obj, link.prod_amount, 0, false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Activates waiting consumers according to priotrity until available power is used.
|
||||
private func ActivateConsumers(int power_available)
|
||||
{
|
||||
// Debugging logs.
|
||||
Log("POWR - ActivateConsumers(): network = %v, frame = %d, power_available = %d", this, FrameCounter(), power_available);
|
||||
var power_used = 0;
|
||||
// Sort the waiting consumers according to priority and then activate consumers until available power is used.
|
||||
if (GetLength(lib_waiting_consumers) > 1) SortArrayByProperty(lib_waiting_consumers, "priority");
|
||||
for (var index = GetLength(lib_waiting_consumers) - 1; index >= 0; index--)
|
||||
{
|
||||
var link = lib_waiting_consumers[index];
|
||||
// If this consumer requires to much power try one of lower priority.
|
||||
if (power_used + link.cons_amount > power_available)
|
||||
continue;
|
||||
power_used += link.cons_amount;
|
||||
PushBack(lib_active_consumers, link);
|
||||
link.obj->OnEnoughPower(link.cons_amount);
|
||||
lib_power_balance -= link.cons_amount;
|
||||
RemoveArrayIndex(lib_waiting_consumers, index);
|
||||
VisualizePowerChange(link.obj, 0, link.cons_amount, false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Deactivates active consumers according to priority until power need is satisfied.
|
||||
private func DeactivateConsumers(int power_need)
|
||||
{
|
||||
// Debugging logs.
|
||||
Log("POWR - DeactivateConsumers(): network = %v, frame = %d, power_need = %d", this, FrameCounter(), power_need);
|
||||
var power_restored = 0;
|
||||
// Sort the active consumers according to priority and then deactivate consumers until balance is restored.
|
||||
if (GetLength(lib_active_consumers) > 1) SortArrayByProperty(lib_active_consumers, "priority", true);
|
||||
for (var index = GetLength(lib_active_consumers) - 1; index >= 0; index--)
|
||||
{
|
||||
var link = lib_active_consumers[index];
|
||||
power_restored += link.cons_amount;
|
||||
PushBack(lib_waiting_consumers, link);
|
||||
link.obj->OnNotEnoughPower(link.cons_amount);
|
||||
lib_power_balance += link.cons_amount;
|
||||
SetLength(lib_active_consumers, index);
|
||||
VisualizePowerChange(link.obj, link.cons_amount, 0, true);
|
||||
// Stop deactivating consumers if enough power has been freed.
|
||||
if (power_restored >= power_need)
|
||||
return true;
|
||||
}
|
||||
// This should not ever happen, so put a log here.
|
||||
Log("Not enough power consumers to deactivate for restoring the power balance. How could this happen?");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*-- Logging --*/
|
||||
|
||||
private func LogState(string tag)
|
||||
{
|
||||
Log("==========================================================================");
|
||||
Log("POWR - State for network %v in frame %d with tag %s", this, FrameCounter(), tag);
|
||||
Log("==========================================================================");
|
||||
Log("POWR - lib_neutral_network: %v", lib_neutral_network);
|
||||
Log("POWR - lib_idle_producers: %v", lib_idle_producers);
|
||||
Log("POWR - lib_active_producers: %v", lib_active_producers);
|
||||
Log("POWR - lib_waiting_consumers: %v", lib_waiting_consumers);
|
||||
Log("POWR - lib_active_consumers: %v", lib_active_consumers);
|
||||
Log("POWR - lib_power_balance = %d", lib_power_balance);
|
||||
Log("POWR - surplus: %d", GetPowerSurplus());
|
||||
Log("==========================================================================");
|
||||
return;
|
||||
}
|
||||
|
||||
/*-- Power Visualization --*/
|
||||
|
||||
// Visualizes the power change on an object.
|
||||
private func VisualizePowerChange(object obj, int to, int before, bool loss)
|
||||
// Visualizes the power change on an object from before to to.
|
||||
private func VisualizePowerChange(object obj, int old_val, int new_val, bool loss)
|
||||
{
|
||||
// Safety: object must exist.
|
||||
if (!obj)
|
||||
return FatalError("VisualizePowerChange() is called for a non-existing object.");
|
||||
|
||||
var before_current = nil;
|
||||
var effect = GetEffect("VisualPowerChange", obj);
|
||||
if (!effect)
|
||||
|
@ -416,25 +535,25 @@ private func VisualizePowerChange(object obj, int to, int before, bool loss)
|
|||
else
|
||||
before_current = effect.current;
|
||||
|
||||
var to_abs = Abs(to);
|
||||
var before_abs = Abs(before);
|
||||
var old_abs = Abs(old_val);
|
||||
var new_abs = Abs(new_val);
|
||||
|
||||
effect.max = Max(to_abs, before_abs);
|
||||
effect.current = before_current ?? before_abs;
|
||||
effect.to = to_abs;
|
||||
effect.max = Max(old_abs, new_abs);
|
||||
effect.current = before_current ?? old_abs;
|
||||
effect.to = new_abs;
|
||||
|
||||
if (loss)
|
||||
effect.back_graphics_name = "Red";
|
||||
else
|
||||
effect.back_graphics_name = nil;
|
||||
|
||||
if (to < 0)
|
||||
if (new_val < 0)
|
||||
effect.graphics_name = "Yellow";
|
||||
else if (to > 0)
|
||||
else if (new_val > 0)
|
||||
effect.graphics_name = "Green";
|
||||
else // off now
|
||||
{
|
||||
if (before < 0)
|
||||
if (old_val < 0)
|
||||
effect.graphics_name = "Yellow";
|
||||
else
|
||||
effect.graphics_name = "Green";
|
||||
|
@ -449,8 +568,10 @@ protected func FxVisualPowerChangeRefresh(object target, proplist effect)
|
|||
effect.bar->Close();
|
||||
var vis = VIS_Allies | VIS_Owner;
|
||||
var controller = target->GetController();
|
||||
|
||||
if (controller == NO_OWNER)
|
||||
vis = VIS_All;
|
||||
|
||||
var off_x = -(target->GetDefCoreVal("Width", "DefCore") * 3) / 8;
|
||||
var off_y = target->GetDefCoreVal("Height", "DefCore") / 2 - 10;
|
||||
|
||||
|
|
|
@ -531,9 +531,14 @@ protected func FxProcessProductionStart(object target, proplist effect, int temp
|
|||
// Callback to the producer.
|
||||
this->~OnProductionStart(effect.Product);
|
||||
|
||||
// consume power
|
||||
if(PowerNeed() > 0)
|
||||
MakePowerConsumer(PowerNeed());
|
||||
// Consume power by registering as a consumer for the needed amount.
|
||||
// But first hold the production until the power system gives it ok.
|
||||
if (PowerNeed() > 0)
|
||||
{
|
||||
this->~OnProductionHold(effect.Product, effect.Duration);
|
||||
effect.Active = false;
|
||||
RegisterPowerRequest(PowerNeed());
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -541,7 +546,7 @@ protected func FxProcessProductionStart(object target, proplist effect, int temp
|
|||
public func OnNotEnoughPower()
|
||||
{
|
||||
var effect = GetEffect("ProcessProduction", this);
|
||||
if(effect)
|
||||
if (effect)
|
||||
{
|
||||
effect.Active = false;
|
||||
this->~OnProductionHold(effect.Product, effect.Duration);
|
||||
|
@ -554,7 +559,7 @@ public func OnNotEnoughPower()
|
|||
public func OnEnoughPower()
|
||||
{
|
||||
var effect = GetEffect("ProcessProduction", this);
|
||||
if(effect)
|
||||
if (effect)
|
||||
{
|
||||
effect.Active = true;
|
||||
this->~OnProductionContinued(effect.Product, effect.Duration);
|
||||
|
@ -586,7 +591,7 @@ protected func FxProcessProductionStop(object target, proplist effect, int reaso
|
|||
if(temp) return;
|
||||
|
||||
// no need to consume power anymore
|
||||
UnmakePowerConsumer();
|
||||
UnregisterPowerRequest();
|
||||
|
||||
if (reason != 0)
|
||||
return 1;
|
||||
|
|
|
@ -14,14 +14,14 @@ protected func Initialize()
|
|||
return;
|
||||
|
||||
// If there are no power consumers yet, there is nothing to be done.
|
||||
if (Library_Power_power_compounds == nil)
|
||||
if (LIB_POWR_Networks == nil)
|
||||
return;
|
||||
|
||||
// Update all consumers forcefully.
|
||||
var remember = [];
|
||||
|
||||
// Get all power compounds (bases).
|
||||
for (var base in Library_Power_power_compounds)
|
||||
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)
|
||||
|
@ -90,12 +90,8 @@ public func DestructionEx()
|
|||
{
|
||||
var request = obj.last_request;
|
||||
var amount = obj.last_amount;
|
||||
// Did not requested power aka "is not running".
|
||||
if (request == PowerConsumer_LPR_None)
|
||||
continue;
|
||||
// Temporarily stop consuming power to make sure the callback order is correct.
|
||||
obj->OnNotEnoughPower();
|
||||
obj.last_request = PowerConsumer_LPR_None;
|
||||
obj.last_amount = 0;
|
||||
obj->MakePowerConsumer(amount);
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ public func IsProduct(id product_id)
|
|||
}
|
||||
|
||||
private func ProductionTime(id toProduce) { return 100; }
|
||||
private func PowerNeed() { return 100; }
|
||||
private func PowerNeed() { return 150; }
|
||||
|
||||
public func OnProductionStart(id product)
|
||||
{
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
/**
|
||||
BurningBattery
|
||||
Burning Battery
|
||||
A part of a compensator!
|
||||
|
||||
@author Zapper
|
||||
*/
|
||||
|
||||
local Name = "$Name$";
|
||||
local Description = "$Description$";
|
||||
local Collectible = 0;
|
||||
local time;
|
||||
|
||||
func Initialize()
|
||||
|
@ -23,4 +22,11 @@ func DoSmoke()
|
|||
{
|
||||
++time;
|
||||
Smoke(RandomX(-5, 5), RandomX(-5, 5), 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-- Properties --*/
|
||||
|
||||
local Name = "$Name$";
|
||||
local Description = "$Description$";
|
||||
local Collectible = 0;
|
|
@ -1,27 +1,20 @@
|
|||
/**
|
||||
ChargeShower
|
||||
Shows stuff.
|
||||
Shows charge stuff on the compensator.
|
||||
*/
|
||||
|
||||
local Name = "$Name$";
|
||||
local Description = "$Description$";
|
||||
|
||||
|
||||
local current, to;
|
||||
|
||||
local ActMap = {
|
||||
Turn = {
|
||||
Prototype = Action,
|
||||
Name = "Turn",
|
||||
Procedure = DFA_ATTACH,
|
||||
Length=6,
|
||||
Delay=4,
|
||||
X = 0,
|
||||
Y = 0,
|
||||
Wdt = 11,
|
||||
Hgt = 19,
|
||||
NextAction = "Turn"
|
||||
}
|
||||
};
|
||||
|
||||
public func Initialize()
|
||||
{
|
||||
to = 0;
|
||||
current = 0;
|
||||
Set(to);
|
||||
return;
|
||||
}
|
||||
|
||||
func AttachTargetLost()
|
||||
{
|
||||
|
@ -31,16 +24,16 @@ func AttachTargetLost()
|
|||
func To(int i)
|
||||
{
|
||||
to = i;
|
||||
if(!GetEffect("Adjust", this))
|
||||
if (!GetEffect("Adjust", this))
|
||||
AddEffect("Adjust", this, 1, 2, this);
|
||||
}
|
||||
|
||||
func FxAdjustTimer()
|
||||
{
|
||||
if(current == to)
|
||||
if (current == to)
|
||||
return -1;
|
||||
|
||||
if(current < to)
|
||||
if (current < to)
|
||||
++current;
|
||||
else --current;
|
||||
|
||||
|
@ -51,7 +44,7 @@ func FxAdjustTimer()
|
|||
|
||||
func Set(int i)
|
||||
{
|
||||
SetObjDrawTransform((800 * i)/100, 0, -500, 0, 900, -150);
|
||||
SetObjDrawTransform((800 * i) / 100, 0, -500, 0, 900, -150);
|
||||
}
|
||||
|
||||
func Init(to)
|
||||
|
@ -64,12 +57,26 @@ func Init(to)
|
|||
this.Plane = to.Plane + 1;
|
||||
}
|
||||
|
||||
public func Initialize()
|
||||
{
|
||||
to=0;
|
||||
current=0;
|
||||
Set(to);
|
||||
return true;
|
||||
}
|
||||
|
||||
public func SaveScenarioObject() { return false; }
|
||||
|
||||
|
||||
/*-- Properties --*/
|
||||
|
||||
local ActMap = {
|
||||
Turn = {
|
||||
Prototype = Action,
|
||||
Name = "Turn",
|
||||
Procedure = DFA_ATTACH,
|
||||
Length=6,
|
||||
Delay=4,
|
||||
X = 0,
|
||||
Y = 0,
|
||||
Wdt = 11,
|
||||
Hgt = 19,
|
||||
NextAction = "Turn"
|
||||
}
|
||||
};
|
||||
|
||||
local Name = "$Name$";
|
||||
local Description = "$Description$";
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
/*-- compensator --*/
|
||||
/**
|
||||
Compensator
|
||||
A small structure which stores surplus energy available in a network.
|
||||
|
||||
@author Zapper, Maikel
|
||||
*/
|
||||
|
||||
#include Library_Structure
|
||||
#include Library_Ownable
|
||||
|
@ -8,189 +13,253 @@
|
|||
|
||||
local DefaultFlagRadius = 90;
|
||||
|
||||
static const Compensator_max_seconds = 15;
|
||||
static const Compensator_power_usage = 50;
|
||||
// Power storage variables.
|
||||
local stored_power;
|
||||
static const POWR_COMP_PowerUsage = 50;
|
||||
static const POWR_COMP_MaxStorage = 27000; // 15 * 36 * 50
|
||||
|
||||
local power_seconds;
|
||||
// Variables for displaying the charge.
|
||||
local leftcharge, rightcharge, anim;
|
||||
|
||||
|
||||
local Name = "$Name$";
|
||||
local Description = "$Description$";
|
||||
local leftcharge, rightcharge, lastcharge;
|
||||
local anim;
|
||||
|
||||
func Construction(object creator)
|
||||
protected func Construction(object creator)
|
||||
{
|
||||
power_seconds = 0;
|
||||
lastcharge = 0;
|
||||
|
||||
stored_power = 0;
|
||||
anim = PlayAnimation("Charge", 1, Anim_Const(GetAnimationLength("Charge")), Anim_Const(1000));
|
||||
|
||||
SetAction("Default");
|
||||
return _inherited(creator, ...);
|
||||
}
|
||||
|
||||
func Initialize()
|
||||
protected func Initialize()
|
||||
{
|
||||
leftcharge = CreateObjectAbove(Compensator_ChargeShower, 7 * GetCalcDir(), 10, NO_OWNER);
|
||||
leftcharge->Init(this);
|
||||
rightcharge = CreateObjectAbove(Compensator_ChargeShower, -6 * GetCalcDir(), 10, NO_OWNER);
|
||||
rightcharge->Init(this);
|
||||
AddTimer("EnergyCheck", 100);
|
||||
AddTimer("PowerCheck", 10);
|
||||
return _inherited(...);
|
||||
}
|
||||
|
||||
public func GetProducerPriority() { return 50 * (power_seconds - Compensator_max_seconds) / Compensator_max_seconds; }
|
||||
protected func Incineration()
|
||||
{
|
||||
if (stored_power == 0)
|
||||
return Extinguish();
|
||||
|
||||
for (var i = 0; i < 2; ++i)
|
||||
{
|
||||
var x = -7 + 14 * i;
|
||||
var b = CreateObject(Compensator_BurningBattery, x, 6, NO_OWNER);
|
||||
// Set controller for correct kill tracing.
|
||||
b->SetController(GetController());
|
||||
b->SetSpeed(-30 + 60 * i + RandomX(-10, 10), RandomX(-50, -30));
|
||||
}
|
||||
return Explode(30);
|
||||
}
|
||||
|
||||
|
||||
/*-- Power --*/
|
||||
|
||||
public func SetCharge(int to)
|
||||
{
|
||||
stored_power = BoundBy(to, 0, POWR_COMP_MaxStorage);
|
||||
RefreshAnimationPosition();
|
||||
return;
|
||||
}
|
||||
|
||||
private func PowerCheck()
|
||||
{
|
||||
// Not fully constructed or neutral compensators don't do anything.
|
||||
if (GetCon() < 100 || GetOwner() == NO_OWNER)
|
||||
return;
|
||||
|
||||
// Register as producer while still consuming if power level is above 2/3.
|
||||
if (GetEffect("ConsumePower", this))
|
||||
{
|
||||
if (stored_power >= 2 * POWR_COMP_MaxStorage / 3)
|
||||
RegisterPowerProduction(POWR_COMP_PowerUsage);
|
||||
return;
|
||||
}
|
||||
|
||||
// Register as consumer while still producing if power level is below 1/3.
|
||||
if (GetEffect("ProducePower", this))
|
||||
{
|
||||
if (stored_power <= 1 * POWR_COMP_MaxStorage / 3)
|
||||
RegisterPowerRequest(POWR_COMP_PowerUsage);
|
||||
return;
|
||||
}
|
||||
|
||||
// Register as consumer if stored power is zero.
|
||||
if (stored_power == 0)
|
||||
{
|
||||
RegisterPowerRequest(POWR_COMP_PowerUsage);
|
||||
return;
|
||||
}
|
||||
|
||||
// Register as producer if storage is full.
|
||||
if (stored_power >= POWR_COMP_MaxStorage)
|
||||
{
|
||||
RegisterPowerProduction(POWR_COMP_PowerUsage);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*-- Power Production --*/
|
||||
|
||||
// Produces power on demand, so not steady.
|
||||
public func IsSteadyPowerProducer() { return false; }
|
||||
|
||||
// Producer priority depends on the amount of power that is stored.
|
||||
public func GetProducerPriority() { return 50 * (2 * stored_power - POWR_COMP_MaxStorage) / POWR_COMP_MaxStorage; }
|
||||
|
||||
// Callback from the power library for production of power request.
|
||||
public func OnPowerProductionStart(int amount)
|
||||
{
|
||||
// Start the production of power.
|
||||
if (!GetEffect("ProducePower", this))
|
||||
AddEffect("ProducePower", this, 1, 2, this);
|
||||
// Stop the consumption of power.
|
||||
if (GetEffect("ConsumePower", this))
|
||||
{
|
||||
RemoveEffect("ConsumePower", this);
|
||||
// Notify the power network.
|
||||
UnregisterPowerRequest();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Callback from the power library requesting to stop power production.
|
||||
public func OnPowerProductionStop()
|
||||
{
|
||||
// Stop the production of power.
|
||||
if (GetEffect("ProducePower", this))
|
||||
RemoveEffect("ProducePower", this);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected func FxProducePowerStart(object target, proplist effect, int temp)
|
||||
{
|
||||
if (temp)
|
||||
return 1;
|
||||
// Set Interval to 2.
|
||||
effect.Interval = 2;
|
||||
// Sparkle effect when releasing power.
|
||||
if (!GetEffect("Sparkle", this))
|
||||
AddEffect("Sparkle", this, 1, 1, this);
|
||||
return 1;
|
||||
}
|
||||
|
||||
protected func FxProducePowerTimer(object target, proplist effect, time)
|
||||
{
|
||||
// Increase the stored power.
|
||||
stored_power -= effect.Interval * POWR_COMP_PowerUsage;
|
||||
// Refresh the animation.
|
||||
RefreshAnimationPosition();
|
||||
// If stored power is zero then stop producing power.
|
||||
if (stored_power <= 0)
|
||||
{
|
||||
// Notify the power network.
|
||||
UnregisterPowerProduction();
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
protected func FxProducePowerStop(object target, proplist effect, int reason, bool temp)
|
||||
{
|
||||
if (temp)
|
||||
return 1;
|
||||
if (GetEffect("Sparkle", this))
|
||||
RemoveEffect("Sparkle", this);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*-- Power Consumption --*/
|
||||
|
||||
// It has a low consumer priority so that all other consumers are supplied first.
|
||||
public func GetConsumerPriority() { return 0; }
|
||||
|
||||
func OnNotEnoughPower()
|
||||
// Callback from the power library saying there is enough power.
|
||||
public func OnEnoughPower()
|
||||
{
|
||||
// not enough power to sustain a battery - turn off
|
||||
if(GetEffect("ConsumePower", this))
|
||||
// Start the consumption of power.
|
||||
if (!GetEffect("ConsumePower", this))
|
||||
AddEffect("ConsumePower", this, 1, 2, this);
|
||||
// Stop the production of power.
|
||||
if (GetEffect("ProducePower", this))
|
||||
{
|
||||
RemoveEffect("ProducePower", this);
|
||||
// Notify the power network.
|
||||
UnregisterPowerProduction();
|
||||
}
|
||||
return _inherited(...);
|
||||
}
|
||||
|
||||
// Callback from the power library saying there is not enough power.
|
||||
public func OnNotEnoughPower()
|
||||
{
|
||||
if (GetEffect("ConsumePower", this))
|
||||
RemoveEffect("ConsumePower", this);
|
||||
|
||||
ScheduleCall(this, "UnmakePowerConsumer", 1, 0);
|
||||
return _inherited(...);
|
||||
}
|
||||
|
||||
// devour energy
|
||||
func OnEnoughPower()
|
||||
protected func FxConsumePowerStart(object target, proplist effect, int temp)
|
||||
{
|
||||
if(!GetEffect("ConsumePower", this))
|
||||
AddEffect("ConsumePower", this, 1, 36, this);
|
||||
return _inherited(...);
|
||||
if (temp)
|
||||
return 1;
|
||||
// Set Interval to 2.
|
||||
effect.Interval = 2;
|
||||
return 1;
|
||||
}
|
||||
|
||||
func SetCharge(int to)
|
||||
protected func FxConsumePowerTimer(object target, proplist effect, int time)
|
||||
{
|
||||
power_seconds = BoundBy(to, 0, Compensator_max_seconds);
|
||||
// Increase the stored power.
|
||||
stored_power += effect.Interval * POWR_COMP_PowerUsage;
|
||||
// Refresh the animation.
|
||||
RefreshAnimationPosition();
|
||||
// If fully charged remove this effect.
|
||||
if (stored_power >= POWR_COMP_MaxStorage)
|
||||
{
|
||||
// Notify the power network.
|
||||
UnregisterPowerRequest();
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
func RefreshAnimationPosition()
|
||||
protected func FxConsumePowerStop(object target, proplist effect, int reason, bool temp)
|
||||
{
|
||||
var charge = (power_seconds * 100) / Compensator_max_seconds;
|
||||
if (temp)
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*-- Animations & Effects --*/
|
||||
|
||||
private func RefreshAnimationPosition()
|
||||
{
|
||||
var charge = (stored_power * 100) / POWR_COMP_MaxStorage;
|
||||
/*var current = GetAnimationPosition(anim);
|
||||
var len = GetAnimationLength("Charge");
|
||||
SetAnimationPosition(anim, Anim_Linear(current, current, len - (charge * len) / 100, 35, ANIM_Hold));*/
|
||||
leftcharge->To(Min(charge, 50)*2);
|
||||
rightcharge->To(Max(0, charge-50)*2);
|
||||
}
|
||||
|
||||
func FxConsumePowerTimer(target, effect, time)
|
||||
{
|
||||
++power_seconds;
|
||||
RefreshAnimationPosition();
|
||||
// fully charged?
|
||||
if(power_seconds >= Compensator_max_seconds)
|
||||
{
|
||||
UnmakePowerConsumer();
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
func EnergyCheck()
|
||||
{
|
||||
if(GetCon() < 100) return;
|
||||
|
||||
// consuming - everything is alright
|
||||
if(GetEffect("ConsumePower", this))
|
||||
return true;
|
||||
// producing - nothing to change either
|
||||
if(GetEffect("ProducePower", this))
|
||||
return true;
|
||||
|
||||
// neutral compensators don't do anything
|
||||
if(GetOwner() == NO_OWNER) return false;
|
||||
|
||||
// are we needed?
|
||||
if(power_seconds > 0)
|
||||
{
|
||||
var s = GetPendingPowerAmount();
|
||||
if(s > 0)
|
||||
{
|
||||
// turn on, start the machines!
|
||||
AddEffect("ProducePower", this, 1, 36, this);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// fully charged
|
||||
if(power_seconds >= Compensator_max_seconds)
|
||||
return false;
|
||||
|
||||
// can we leech power?
|
||||
var p = GetCurrentPowerBalance();
|
||||
|
||||
// we have some play here?
|
||||
if(p >= Compensator_power_usage)
|
||||
{
|
||||
MakePowerConsumer(Compensator_power_usage);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
func FxProducePowerStart(target, effect, temp)
|
||||
{
|
||||
if(temp) return;
|
||||
MakePowerProducer(Compensator_power_usage);
|
||||
|
||||
// todo: effects
|
||||
AddEffect("Sparkle", this, 1, 1, this);
|
||||
}
|
||||
|
||||
func FxSparkleTimer(target, effect, time)
|
||||
protected func FxSparkleTimer(object target, proplist effect, int time)
|
||||
{
|
||||
effect.Interval *= 2;
|
||||
if(effect.Interval > 35*3) return -1;
|
||||
if (effect.Interval > 35 * 3)
|
||||
return -1;
|
||||
CreateParticle("StarSpark", PV_Random(-3, 3), PV_Random(-14, -10), PV_Random(-5, 5), PV_Random(-8, 0), 10, Particles_Magic(), 4);
|
||||
}
|
||||
|
||||
func FxProducePowerTimer(target, effect, time)
|
||||
{
|
||||
--power_seconds;
|
||||
RefreshAnimationPosition();
|
||||
if(power_seconds <= 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// stop when not needed
|
||||
if((GetCurrentPowerBalance() >= Compensator_power_usage) && GetPendingPowerAmount() == 0)
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
func FxProducePowerStop(target, effect, reason, temp)
|
||||
{
|
||||
if(temp) return;
|
||||
MakePowerProducer(0);
|
||||
|
||||
if(GetEffect("Sparkle", this))
|
||||
RemoveEffect("Sparkle", this);
|
||||
}
|
||||
|
||||
func Incineration()
|
||||
{
|
||||
if(power_seconds == 0)
|
||||
return Extinguish();
|
||||
|
||||
|
||||
for(var i = 0; i < 2; ++i)
|
||||
{
|
||||
var x = -7 + 14 * i;
|
||||
var b = CreateObjectAbove(Compensator_BurningBattery, x, 6, NO_OWNER);
|
||||
b->SetController(GetController()); // killtracing
|
||||
|
||||
b->SetSpeed(-30 + 60 * i + RandomX(-10, 10), RandomX(-50, -30));
|
||||
}
|
||||
|
||||
Explode(30);
|
||||
}
|
||||
/*-- Properties --*/
|
||||
|
||||
local ActMap = {
|
||||
Default = {
|
||||
|
@ -205,6 +274,9 @@ local ActMap = {
|
|||
NextAction = "Default",
|
||||
},
|
||||
};
|
||||
|
||||
local Name = "$Name$";
|
||||
local Description = "$Description$";
|
||||
local BlastIncinerate = 1;
|
||||
local HitPoints = 25;
|
||||
local ContactIncinerate = 1;
|
||||
|
|
|
@ -70,6 +70,7 @@ func Destruction()
|
|||
wood->SetXDir(RandomX(-10, 10));
|
||||
wood->SetYDir(RandomX(-2, 0));
|
||||
}
|
||||
return _inherited(...);
|
||||
}
|
||||
|
||||
func LostElevator()
|
||||
|
@ -126,8 +127,8 @@ func ExecuteSync()
|
|||
SetPartnerVertices(partner->GetX() - GetX(), partner->GetY() - GetY());
|
||||
|
||||
// reset power usage
|
||||
UnmakePowerConsumer();
|
||||
partner->UnmakePowerConsumer();
|
||||
//UnmakePowerConsumer();
|
||||
//partner->UnmakePowerConsumer();
|
||||
|
||||
// can now attach partner on one of the new vertices
|
||||
partner->SetAction("Attach", this);
|
||||
|
@ -292,45 +293,38 @@ func FxFetchVehiclesTimer(target, effect, time)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/* Energy */
|
||||
/*-- Power Consumption --*/
|
||||
|
||||
func GetNeededPower()
|
||||
private func GetNeededPower()
|
||||
{
|
||||
var p = Elevator_needed_power;
|
||||
if(partner_was_synced) p = 2 * p;
|
||||
return p;
|
||||
if (partner_was_synced)
|
||||
return 2 * Elevator_needed_power;
|
||||
return Elevator_needed_power;
|
||||
}
|
||||
|
||||
|
||||
// for the position
|
||||
func GetActualPowerConsumer()
|
||||
// The elevator is the actual power consumer.
|
||||
public func GetActualPowerConsumer()
|
||||
{
|
||||
return elevator;
|
||||
}
|
||||
|
||||
// the lift may not need power when not used
|
||||
func QueryWaivePowerRequest()
|
||||
{
|
||||
// no clonk on elevator? must be automatic
|
||||
if(CheckIdle()) return 20;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Elevator has a high priority.
|
||||
public func GetConsumerPriority() { return 100; }
|
||||
|
||||
func OnNotEnoughPower()
|
||||
public func OnNotEnoughPower()
|
||||
{
|
||||
_inherited(...); // on purpose before the rest
|
||||
|
||||
if(GetYDir())
|
||||
if (GetYDir())
|
||||
StoreMovementData();
|
||||
else; // already has data stored
|
||||
|
||||
if(GetAction() != "DriveIdle")
|
||||
if (GetAction() != "DriveIdle")
|
||||
Halt(false, true);
|
||||
}
|
||||
|
||||
func OnEnoughPower()
|
||||
public func OnEnoughPower()
|
||||
{
|
||||
_inherited(...); // on purpose before the rest
|
||||
RestoreMovementData();
|
||||
|
@ -393,7 +387,7 @@ func SetMoveDirection(int dir, bool user_requested, bool drill)
|
|||
speed = GetDrillSpeed();
|
||||
}
|
||||
|
||||
if(CurrentlyHasPower())
|
||||
//if(CurrentlyHasPower())
|
||||
{
|
||||
SetYDir(dir * speed);
|
||||
SetAction(action);
|
||||
|
@ -402,10 +396,10 @@ func SetMoveDirection(int dir, bool user_requested, bool drill)
|
|||
|
||||
elevator->StartEngine();
|
||||
}
|
||||
else
|
||||
//else
|
||||
{
|
||||
StoreMovementData(dir * speed, action);
|
||||
MakePowerConsumer(GetNeededPower());
|
||||
// MakePowerConsumer(GetNeededPower());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -428,7 +422,7 @@ func Halt(bool user_requested, bool power_out)
|
|||
|
||||
if(user_requested)
|
||||
{
|
||||
UnmakePowerConsumer();
|
||||
//UnmakePowerConsumer();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -440,7 +434,7 @@ func Halt(bool user_requested, bool power_out)
|
|||
|
||||
func FxStopPowerConsumptionTimer(object target, effect, int time)
|
||||
{
|
||||
UnmakePowerConsumer();
|
||||
//UnmakePowerConsumer();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,66 +1,18 @@
|
|||
/*--
|
||||
/**
|
||||
Pump
|
||||
Author: Maikel, ST-DDT, Sven2, Newton
|
||||
|
||||
Pumps liquids using drain and source pipes. Features include:
|
||||
+ switch on and off
|
||||
+ consume/produce a variable amount of power depending on the height of
|
||||
source and drain
|
||||
|
||||
--*/
|
||||
@author Maikel, ST-DDT, Sven2, Newton
|
||||
*/
|
||||
|
||||
#include Library_Structure
|
||||
#include Library_Ownable
|
||||
#include Library_PowerConsumer
|
||||
#include Library_PowerProducer
|
||||
|
||||
local Name = "$Name$";
|
||||
local Description = "$Description$";
|
||||
local BlastIncinerate = 50;
|
||||
local HitPoints = 70;
|
||||
|
||||
/*
|
||||
States
|
||||
"Wait": turned off or source pipe not connected
|
||||
"WaitForPower": turned on but no power (does consume power)
|
||||
"WaitForLiquid": turned on but no liquid (does not consume power)
|
||||
"Pump": currently working and consuming/producing power
|
||||
|
||||
*/
|
||||
local ActMap = {
|
||||
Pump = {
|
||||
Prototype = Action,
|
||||
Name = "Pump",
|
||||
Length = 30,
|
||||
Delay = 3,
|
||||
Sound = "Pumpjack",
|
||||
NextAction = "Pump",
|
||||
StartCall = "CheckState",
|
||||
PhaseCall = "Pumping"
|
||||
},
|
||||
Wait = {
|
||||
Prototype = Action,
|
||||
Name = "Wait",
|
||||
Delay = 90,
|
||||
NextAction = "Wait",
|
||||
EndCall = "CheckState"
|
||||
},
|
||||
WaitForPower = {
|
||||
Prototype = Action,
|
||||
Name = "WaitForPower",
|
||||
Delay = 30,
|
||||
NextAction = "WaitForPower",
|
||||
EndCall = "CheckState"
|
||||
},
|
||||
WaitForLiquid = {
|
||||
Prototype = Action,
|
||||
Name = "WaitForLiquid",
|
||||
Delay = 30,
|
||||
NextAction = "WaitForLiquid",
|
||||
EndCall = "CheckState"
|
||||
}
|
||||
};
|
||||
|
||||
local animation; // animation handle
|
||||
|
||||
local switched_on; // controlled by Interaction. Indicates whether the user wants to pump or not
|
||||
|
@ -77,18 +29,10 @@ local drain_pipe;
|
|||
/** This object is a liquid pump, thus pipes can be connected. */
|
||||
public func IsLiquidPump() { return true; }
|
||||
|
||||
func Definition(def)
|
||||
{
|
||||
// for title image
|
||||
SetProperty("PictureTransformation",Trans_Rotate(50,0,1,0),def);
|
||||
// for building preview
|
||||
SetProperty("MeshTransformation",Trans_Rotate(50,0,1,0),def);
|
||||
}
|
||||
|
||||
func Construction()
|
||||
{
|
||||
// Rotate at a 45 degree angle towards viewer and add a litte bit of Random
|
||||
this.MeshTransformation = Trans_Rotate(50 + RandomX(-10,10),0,1,0);
|
||||
this.MeshTransformation = Trans_Rotate(50 + RandomX(-10, 10), 0, 1, 0);
|
||||
}
|
||||
|
||||
func Initialize()
|
||||
|
@ -164,24 +108,20 @@ public func SetSource(object pipe)
|
|||
|
||||
/*-- Power stuff --*/
|
||||
|
||||
func QueryWaivePowerRequest()
|
||||
{
|
||||
// has less priority than other objects, but not too low
|
||||
return 10;
|
||||
}
|
||||
|
||||
public func GetConsumerPriority() { return 25; }
|
||||
|
||||
public func GetProducerPriority() { return 100; }
|
||||
|
||||
func OnNotEnoughPower()
|
||||
public func IsSteadyPowerProducer() { return true; }
|
||||
|
||||
public func OnNotEnoughPower()
|
||||
{
|
||||
_inherited(...);
|
||||
powered = false;
|
||||
CheckState();
|
||||
}
|
||||
|
||||
func OnEnoughPower()
|
||||
public func OnEnoughPower()
|
||||
{
|
||||
_inherited(...);
|
||||
powered = true;
|
||||
|
@ -224,13 +164,13 @@ protected func Pumping()
|
|||
{
|
||||
|
||||
// get new materials
|
||||
var aMat = GetSourceObject()->ExtractLiquidAmount(0,0, GetPumpSpeed()/10);
|
||||
var mat = GetSourceObject()->ExtractLiquidAmount(0, 0, GetPumpSpeed()/10);
|
||||
|
||||
// no material to pump?
|
||||
if (aMat)
|
||||
if (mat)
|
||||
{
|
||||
stored_material_index = aMat[0];
|
||||
stored_material_amount = aMat[1];
|
||||
stored_material_index = mat[0];
|
||||
stored_material_amount = mat[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -259,10 +199,9 @@ protected func Pumping()
|
|||
stored_material_index = nil;
|
||||
}
|
||||
|
||||
if(!pump_ok)
|
||||
{
|
||||
if (!pump_ok)
|
||||
SetState("WaitForLiquid");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/** Re check state and change the state if needed */
|
||||
|
@ -326,7 +265,7 @@ private func GetPumpHeight()
|
|||
private func UpdatePowerUsage()
|
||||
{
|
||||
var new_power;
|
||||
if(IsUsingPower())
|
||||
if (IsUsingPower())
|
||||
new_power = PumpHeight2Power(GetPumpHeight());
|
||||
else
|
||||
new_power = 0;
|
||||
|
@ -341,22 +280,23 @@ private func UpdatePowerUsage()
|
|||
if (power_used < 0)
|
||||
{
|
||||
powered = false; // needed since the flag was set manually
|
||||
UnmakePowerProducer();
|
||||
UnregisterPowerProduction();
|
||||
}
|
||||
MakePowerConsumer(new_power);
|
||||
|
||||
RegisterPowerRequest(new_power);
|
||||
}
|
||||
else if (new_power < 0)
|
||||
{
|
||||
if (power_used > 0)
|
||||
UnmakePowerConsumer();
|
||||
MakePowerProducer(-new_power);
|
||||
UnregisterPowerRequest();
|
||||
RegisterPowerProduction(-new_power);
|
||||
powered = true; // when producing, we always have power
|
||||
}
|
||||
else // new_power == 0
|
||||
{
|
||||
if (power_used < 0) UnmakePowerProducer();
|
||||
else if (power_used > 0) UnmakePowerConsumer();
|
||||
if (power_used < 0)
|
||||
UnregisterPowerProduction();
|
||||
else if (power_used > 0)
|
||||
UnregisterPowerRequest();
|
||||
powered = true;
|
||||
}
|
||||
|
||||
|
@ -377,7 +317,7 @@ private func PumpHeight2Power(int pump_height)
|
|||
// max power consumed/produced
|
||||
var max_power = 150;
|
||||
|
||||
return BoundBy((pump_height + power_offset)/15*5, -max_power,max_power+power_offset);
|
||||
return BoundBy((pump_height + power_offset) / 15 * 5, -max_power, max_power + power_offset);
|
||||
}
|
||||
|
||||
/** Returns whether there is liquid at the source pipe to pump */
|
||||
|
@ -421,11 +361,73 @@ func SetState(string act)
|
|||
// deactivate power usage when not pumping
|
||||
if (powered && (act == "Wait" || act == "WaitForLiquid"))
|
||||
{
|
||||
if (power_used < 0) UnmakePowerProducer();
|
||||
else if(power_used > 0) UnmakePowerConsumer();
|
||||
if (power_used < 0)
|
||||
UnregisterPowerProduction();
|
||||
else if (power_used > 0)
|
||||
UnregisterPowerRequest();
|
||||
|
||||
power_used = 0;
|
||||
powered = false;
|
||||
}
|
||||
// finally, set the action
|
||||
SetAction(act);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*-- Properties --*/
|
||||
|
||||
protected func Definition(def)
|
||||
{
|
||||
// for title image
|
||||
SetProperty("PictureTransformation", Trans_Rotate(50, 0, 1, 0), def);
|
||||
// for building preview
|
||||
SetProperty("MeshTransformation", Trans_Rotate(50, 0, 1, 0), def);
|
||||
}
|
||||
|
||||
/*
|
||||
States
|
||||
"Wait": turned off or source pipe not connected
|
||||
"WaitForPower": turned on but no power (does consume power)
|
||||
"WaitForLiquid": turned on but no liquid (does not consume power)
|
||||
"Pump": currently working and consuming/producing power
|
||||
|
||||
*/
|
||||
local ActMap = {
|
||||
Pump = {
|
||||
Prototype = Action,
|
||||
Name = "Pump",
|
||||
Length = 30,
|
||||
Delay = 3,
|
||||
Sound = "Pumpjack",
|
||||
NextAction = "Pump",
|
||||
StartCall = "CheckState",
|
||||
PhaseCall = "Pumping"
|
||||
},
|
||||
Wait = {
|
||||
Prototype = Action,
|
||||
Name = "Wait",
|
||||
Delay = 90,
|
||||
NextAction = "Wait",
|
||||
EndCall = "CheckState"
|
||||
},
|
||||
WaitForPower = {
|
||||
Prototype = Action,
|
||||
Name = "WaitForPower",
|
||||
Delay = 30,
|
||||
NextAction = "WaitForPower",
|
||||
EndCall = "CheckState"
|
||||
},
|
||||
WaitForLiquid = {
|
||||
Prototype = Action,
|
||||
Name = "WaitForLiquid",
|
||||
Delay = 30,
|
||||
NextAction = "WaitForLiquid",
|
||||
EndCall = "CheckState"
|
||||
}
|
||||
};
|
||||
|
||||
local Name = "$Name$";
|
||||
local Description = "$Description$";
|
||||
local BlastIncinerate = 50;
|
||||
local HitPoints = 70;
|
||||
|
|
|
@ -1,4 +1,11 @@
|
|||
/*-- Steam engine --*/
|
||||
/**
|
||||
Steam Engine
|
||||
Burns fuels like coal, wood and oil to produce power. The steam engine
|
||||
produces 300 units of power independent of the fuel. However, the fuel
|
||||
determines the amount of fuel and thereby the burn time.
|
||||
|
||||
@author Maikel
|
||||
*/
|
||||
|
||||
#include Library_Structure
|
||||
#include Library_Ownable
|
||||
|
@ -9,134 +16,158 @@ local DefaultFlagRadius = 200;
|
|||
|
||||
static const SteamEngine_produced_power = 300;
|
||||
|
||||
local iFuelAmount;
|
||||
local power_seconds;
|
||||
// Variable to store the fuel amount currently held in the engine.
|
||||
local fuel_amount;
|
||||
|
||||
func Construction(object creator)
|
||||
protected func Construction()
|
||||
{
|
||||
iFuelAmount = 0;
|
||||
power_seconds = 0;
|
||||
fuel_amount = 0;
|
||||
return _inherited(...);
|
||||
}
|
||||
|
||||
SetAction("Default");
|
||||
protected func Initialize()
|
||||
{
|
||||
SetAction("Idle");
|
||||
AddTimer("ContentsCheck", 30);
|
||||
return _inherited(creator, ...);
|
||||
return _inherited(...);
|
||||
}
|
||||
|
||||
public func IsContainer() { return true; }
|
||||
|
||||
public func GetProducerPriority() { return 0; }
|
||||
|
||||
func RejectCollect(id item, object obj)
|
||||
protected func RejectCollect(id item, object obj)
|
||||
{
|
||||
if (obj->~IsFuel())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
func Collection(object obj, bool put)
|
||||
protected func Collection(object obj, bool put)
|
||||
{
|
||||
Sound("Clonk");
|
||||
}
|
||||
|
||||
func ContentsCheck()
|
||||
public func ContentsCheck()
|
||||
{
|
||||
//Ejects non fuel items immediately
|
||||
// Ejects non fuel items immediately
|
||||
var fuel;
|
||||
if(fuel = FindObject(Find_Container(this), Find_Not(Find_Func("IsFuel"))))
|
||||
{
|
||||
fuel->Exit(-53,21, -20, -1, -1, -30);
|
||||
Sound("Chuff"); //I think a 'chuff' or 'metal clonk' sound could be good here -Ringwaul
|
||||
fuel->Exit(-53, 21, -20, -1, -1, -30);
|
||||
Sound("Chuff");
|
||||
}
|
||||
|
||||
// Still active?
|
||||
if(GetAction() == "Work") return true;
|
||||
// or still warm water in the tank?!
|
||||
if(GetEffect("CreatesPower", this))
|
||||
return true;
|
||||
|
||||
// not needed?
|
||||
if(GetPendingPowerAmount() == 0)
|
||||
return false;
|
||||
|
||||
// Still has some fuel?
|
||||
if(iFuelAmount) return SetAction("Work");
|
||||
|
||||
// Search for new fuel
|
||||
if(fuel = FindObject(Find_Container(this), Find_Func("IsFuel")))
|
||||
// If active don't do anything.
|
||||
if (GetAction() == "Work")
|
||||
return;
|
||||
|
||||
// If there is fuel available let the network know.
|
||||
if (fuel_amount > 0 || FindObject(Find_Container(this), Find_Func("IsFuel")))
|
||||
RegisterPowerProduction(SteamEngine_produced_power);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*-- Power Production --*/
|
||||
|
||||
// Produces power on demand, so not steady.
|
||||
public func IsSteadyPowerProducer() { return false; }
|
||||
|
||||
// Low priority so that other sources of power are drained before burning fuel.
|
||||
public func GetProducerPriority() { return 0; }
|
||||
|
||||
// Callback from the power library for production of power request.
|
||||
public func OnPowerProductionStart(int amount)
|
||||
{
|
||||
// Check if there is fuel.
|
||||
if (fuel_amount <= 0)
|
||||
{
|
||||
iFuelAmount += fuel->~GetFuelAmount() / 2;
|
||||
// Search for new fuel among the contents.
|
||||
var fuel = FindObject(Find_Container(this), Find_Func("IsFuel"));
|
||||
if (!fuel)
|
||||
return false;
|
||||
// Extract the fuel amount from the new piece of fuel.
|
||||
fuel_amount += fuel->~GetFuelAmount() * 18;
|
||||
fuel->RemoveObject();
|
||||
}
|
||||
// There is enough fuel so start producing power and notify network of this.
|
||||
if (GetAction() == "Idle")
|
||||
SetAction("Work");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
func ConsumeFuel()
|
||||
{
|
||||
if(iFuelAmount > 0)
|
||||
{
|
||||
// every fuel unit gives power for one second
|
||||
--iFuelAmount;
|
||||
power_seconds += 1;
|
||||
if(!GetEffect("CreatesPower", this))
|
||||
AddEffect("CreatesPower", this, 1, 36, this);
|
||||
}
|
||||
|
||||
// All used up?
|
||||
if(!iFuelAmount || ((GetPendingPowerAmount() == 0) && (GetCurrentPowerBalance() >= SteamEngine_produced_power)))
|
||||
{
|
||||
SetAction("Default");
|
||||
ContentsCheck();
|
||||
}
|
||||
}
|
||||
|
||||
func FxCreatesPowerStart(target, effect, temp)
|
||||
// Callback from the power library requesting to stop power production.
|
||||
public func OnPowerProductionStop()
|
||||
{
|
||||
// Set action to idle when it was working.
|
||||
if (GetAction() == "Work")
|
||||
SetAction("Idle");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Start call from working action.
|
||||
protected func WorkStart()
|
||||
{
|
||||
if(temp) return;
|
||||
// fixed amount
|
||||
MakePowerProducer(SteamEngine_produced_power);
|
||||
|
||||
AddEffect("Smoking", this, 1, 5, this);
|
||||
Sound("SteamEngine", false, nil, nil, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
func FxCreatesPowerTimer(target, effect)
|
||||
// Phase call from working action, every two frames.
|
||||
protected func Working()
|
||||
{
|
||||
if(power_seconds == 0) return -1;
|
||||
--power_seconds;
|
||||
// Reduce the fuel amount by 1 per frame.
|
||||
fuel_amount -= 2;
|
||||
// Check if there is still enough fuel available.
|
||||
if (fuel_amount <= 0)
|
||||
{
|
||||
// Search for new fuel among the contents.
|
||||
var fuel = FindObject(Find_Container(this), Find_Func("IsFuel"));
|
||||
if (!fuel)
|
||||
{
|
||||
// Set action to idle and unregister this producer as available from the network.
|
||||
SetAction("Idle");
|
||||
UnregisterPowerProduction();
|
||||
return;
|
||||
}
|
||||
// Extract the fuel amount from the new piece of fuel.
|
||||
fuel_amount += fuel->~GetFuelAmount() * 18;
|
||||
fuel->RemoveObject();
|
||||
}
|
||||
// Smoke from the exhaust shaft.
|
||||
Smoke(-20 * GetCalcDir() + RandomX(-2, 2), -26, 10);
|
||||
Smoke(-20 * GetCalcDir() + RandomX(-2, 2), -24, 8);
|
||||
Smoke(-20 * GetCalcDir() + RandomX(-2, 2), -24, 10);
|
||||
return;
|
||||
}
|
||||
|
||||
func FxCreatesPowerStop(target, effect, reason, temp)
|
||||
// Stop call from working action.
|
||||
protected func WorkStop()
|
||||
{
|
||||
if(temp) return;
|
||||
// disable producer
|
||||
MakePowerProducer(0);
|
||||
|
||||
if(GetEffect("Smoking", this))
|
||||
RemoveEffect("Smoking", this);
|
||||
// Don't kill the sound in this call, since that would interupt the sound effect.
|
||||
return;
|
||||
}
|
||||
|
||||
// Abort call from working action.
|
||||
protected func WorkAbort()
|
||||
{
|
||||
// Sound can be safely stopped here since this action will always end with an abort call.
|
||||
Sound("SteamEngine", false, nil, nil, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
func FxSmokingTimer()
|
||||
{
|
||||
Smoke(-20 * GetCalcDir(), -26, 10);
|
||||
Smoke(-20 * GetCalcDir(), -24, 8);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-- Properties --*/
|
||||
|
||||
local ActMap = {
|
||||
Default = {
|
||||
Idle = {
|
||||
Prototype = Action,
|
||||
Name = "Default",
|
||||
Name = "Idle",
|
||||
Procedure = DFA_NONE,
|
||||
Directions = 2,
|
||||
FlipDir = 1,
|
||||
Length = 1,
|
||||
Delay = 0,
|
||||
FacetBase=1,
|
||||
NextAction = "Default",
|
||||
FacetBase = 1,
|
||||
NextAction = "Idle",
|
||||
},
|
||||
Work = {
|
||||
Prototype = Action,
|
||||
|
@ -149,13 +180,19 @@ local ActMap = {
|
|||
FacetBase = 1,
|
||||
NextAction = "Work",
|
||||
Animation = "Work",
|
||||
EndCall = "ConsumeFuel",
|
||||
PhaseCall = "Working",
|
||||
StartCall = "WorkStart",
|
||||
EndCall = "WorkStop",
|
||||
AbortCall = "WorkAbort",
|
||||
},
|
||||
};
|
||||
|
||||
func Definition(def) {
|
||||
SetProperty("MeshTransformation", Trans_Mul(Trans_Rotate(25,0,1,0), Trans_Scale(625)), def);
|
||||
protected func Definition(def)
|
||||
{
|
||||
SetProperty("MeshTransformation", Trans_Mul(Trans_Rotate(25, 0, 1, 0), Trans_Scale(625)), def);
|
||||
SetProperty("PictureTransformation", Trans_Mul(Trans_Translate(-4000, -18000, 60000), Trans_Rotate(25, 0, 1, 0), Trans_Scale(625)), def);
|
||||
}
|
||||
|
||||
local ContainBlast = true;
|
||||
local BlastIncinerate = 130;
|
||||
local HitPoints = 100;
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
/*-- Wind generator --*/
|
||||
/**
|
||||
Wind Generator
|
||||
Converts wind into a steady power supply.
|
||||
|
||||
@author Maikel
|
||||
*/
|
||||
|
||||
#include Library_Structure
|
||||
#include Library_Ownable
|
||||
|
@ -7,14 +12,14 @@
|
|||
|
||||
local DefaultFlagRadius = 90;
|
||||
|
||||
/* Initialisierung */
|
||||
/*-- Initialization --*/
|
||||
|
||||
local wind_anim;
|
||||
local last_wind;
|
||||
local last_power;
|
||||
local wheel;
|
||||
|
||||
func TurnAnimation(){return "Turn";}
|
||||
func MinRevolutionTime(){return 4500;} // in frames
|
||||
public func GetProducerPriority() { return 100; }
|
||||
func TurnAnimation() { return "Turn"; }
|
||||
func MinRevolutionTime() { return 4500; } // in frames
|
||||
|
||||
protected func Construction()
|
||||
{
|
||||
|
@ -25,70 +30,98 @@ protected func Construction()
|
|||
protected func Initialize()
|
||||
{
|
||||
// create wheel
|
||||
(this.wheel = CreateObjectAbove(WindGenerator_Wheel, 0, 0, NO_OWNER))->Set(this);
|
||||
wheel = CreateObject(WindGenerator_Wheel, 0, 0, NO_OWNER);
|
||||
wheel->SetParent(this);
|
||||
|
||||
// Start animation
|
||||
wind_anim = PlayAnimation(TurnAnimation(), 5, this.wheel->Anim_R(0, GetAnimationLength(TurnAnimation())), Anim_Const(1000));
|
||||
wind_anim = PlayAnimation(TurnAnimation(), 5, wheel->Anim_R(0, GetAnimationLength(TurnAnimation())), Anim_Const(1000));
|
||||
|
||||
// Set initial position
|
||||
AddTimer("Wind2Turn");
|
||||
AddTimer("Wind2Turn", 4);
|
||||
Wind2Turn();
|
||||
return _inherited(...);
|
||||
}
|
||||
|
||||
// used by the windmill too
|
||||
// returns the wind weighted over several points - not the absolute value!
|
||||
func GetWeightedWind()
|
||||
/*-- Power Production --*/
|
||||
|
||||
// Always produces power, irrespective of the demand.
|
||||
public func IsSteadyPowerProducer() { return true; }
|
||||
|
||||
// High priority so that this drained first.
|
||||
public func GetProducerPriority() { return 100; }
|
||||
|
||||
// Callback from the power library for production of power request.
|
||||
public func OnPowerProductionStart(int amount)
|
||||
{
|
||||
// This is a steady producer, so it is already running.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Callback from the power library requesting to stop power production.
|
||||
public func OnPowerProductionStop()
|
||||
{
|
||||
// This is a steady producer, so don't stop anything.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns the wind weighted over several points.
|
||||
private func GetWeightedWind()
|
||||
{
|
||||
// hardcoded for performance reasons
|
||||
return (
|
||||
(10 * (GetWind(-150, -30))) +
|
||||
(25 * (GetWind(-75, -30))) +
|
||||
(30 * (GetWind(0, -30))) +
|
||||
(25 * (GetWind(+75, -30))) +
|
||||
(10 * (GetWind(+150, -30)))
|
||||
(10 * GetWind(-150, -30)) +
|
||||
(25 * GetWind( -75, -30)) +
|
||||
(30 * GetWind( 0, -30)) +
|
||||
(25 * GetWind( +75, -30)) +
|
||||
(10 * GetWind(+150, -30))
|
||||
) / 100;
|
||||
}
|
||||
|
||||
// used by the windmill too
|
||||
func Wind2Turn()
|
||||
// Turns wind into power and adjusts the power production accordingly.
|
||||
public func Wind2Turn()
|
||||
{
|
||||
if(GetCon() < 100) return;
|
||||
// Only produce power if fully constructed.
|
||||
if (GetCon() < 100)
|
||||
return;
|
||||
|
||||
var current_wind = this->GetWeightedWind();
|
||||
var current_wind = GetWeightedWind();
|
||||
var power = 0;
|
||||
if(this.wheel->Stuck() || this.wheel->HasStopped())
|
||||
|
||||
if (wheel->Stuck() || wheel->HasStopped())
|
||||
{
|
||||
power = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
power = Abs(this.wheel->GetRDir(this->MinRevolutionTime()/90));
|
||||
if(power < 5) power = 0;
|
||||
else power = Max(((power + 5) / 25), 1) * 50;
|
||||
power = Abs(wheel->GetRDir(this->MinRevolutionTime() / 90));
|
||||
if (power < 5)
|
||||
power = 0;
|
||||
else
|
||||
power = Max((power + 5) / 25, 1) * 50;
|
||||
}
|
||||
|
||||
if(last_wind != power)
|
||||
// Register the new power production if it changed.
|
||||
if (last_power != power)
|
||||
{
|
||||
last_wind = power;
|
||||
MakePowerProducer(last_wind);
|
||||
last_power = power;
|
||||
RegisterPowerProduction(last_power);
|
||||
}
|
||||
|
||||
// adjust wheel speed
|
||||
this.wheel->SetRDir(current_wind*90, this->MinRevolutionTime());
|
||||
// make sounds
|
||||
// Adjust the wheel speed.
|
||||
wheel->SetRDir(current_wind * 90, this->MinRevolutionTime());
|
||||
// Make some sounds.
|
||||
if (Abs(current_wind) >= 10 && Random(15 - Abs(current_wind / 10)) < 5)
|
||||
{
|
||||
if (!Random(2))
|
||||
Sound("WoodCreak?",false,nil,nil,nil, 75);
|
||||
else
|
||||
Sound("HingeCreak?",false,nil,nil,nil, 75);
|
||||
}
|
||||
Sound(["WoodCreak?","HingeCreak?"][Random(2)], false, nil, nil, nil, 75);
|
||||
return;
|
||||
}
|
||||
|
||||
func Definition(def) {
|
||||
SetProperty("PictureTransformation", Trans_Mul(Trans_Translate(2000,0,7000),Trans_Rotate(-20,1,0,0),Trans_Rotate(30,0,1,0)), def);
|
||||
|
||||
/*-- Properties --*/
|
||||
|
||||
protected func Definition(def)
|
||||
{
|
||||
SetProperty("PictureTransformation", Trans_Mul(Trans_Translate(2000, 0, 7000), Trans_Rotate(-20, 1, 0, 0), Trans_Rotate(30, 0, 1, 0)), def);
|
||||
}
|
||||
|
||||
local Name = "$Name$";
|
||||
local Description = "$Description$";
|
||||
local BlastIncinerate = 60;
|
||||
|
|
|
@ -1,9 +1,39 @@
|
|||
/**
|
||||
Wheel
|
||||
Invisible helper object. Takes care of collisions.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
protected func Initialize()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public func AttachTargetLost()
|
||||
{
|
||||
// Remove this helper object when the generator is lost.
|
||||
return RemoveObject();
|
||||
}
|
||||
|
||||
public func HasStopped()
|
||||
{
|
||||
return !GetRDir(1000);
|
||||
}
|
||||
|
||||
public func SetParent(object parent, int con)
|
||||
{
|
||||
con = con ?? 100;
|
||||
SetCon(con);
|
||||
SetAction("Turn", parent);
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't duplicate on scenario load.
|
||||
public func SaveScenarioObject() { return false; }
|
||||
|
||||
|
||||
/*-- Proplist --*/
|
||||
|
||||
local ActMap = {
|
||||
Turn = {
|
||||
Prototype = Action,
|
||||
|
@ -14,29 +44,4 @@ local ActMap = {
|
|||
FacetBase=1,
|
||||
NextAction = "Hold",
|
||||
}
|
||||
};
|
||||
|
||||
func Initialize()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
func AttachTargetLost()
|
||||
{
|
||||
return RemoveObject();
|
||||
}
|
||||
|
||||
func HasStopped()
|
||||
{
|
||||
return !GetRDir(1000);
|
||||
}
|
||||
|
||||
func Set(to, con)
|
||||
{
|
||||
con = con ?? 100;
|
||||
SetCon(con);
|
||||
SetAction("Turn", to);
|
||||
}
|
||||
|
||||
// Don't duplicate on scenario load
|
||||
func SaveScenarioObject() { return false; }
|
||||
};
|
|
@ -37,7 +37,7 @@ protected func Construction(object creator)
|
|||
protected func Initialize()
|
||||
{
|
||||
// create wheel
|
||||
(this.wheel = CreateObjectAbove(WindGenerator_Wheel, 0, 0, NO_OWNER))->Set(this, 150);
|
||||
(this.wheel = CreateObject(WindGenerator_Wheel, 0, 0, NO_OWNER))->SetParent(this, 150);
|
||||
|
||||
// Set initial position
|
||||
wind_anim = PlayAnimation(TurnAnimation(), 5, this.wheel->Anim_R(GetAnimationLength(TurnAnimation()), 0), Anim_Const(1000));
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
func Initialize()
|
||||
{
|
||||
var a = [3];
|
||||
RemoveArrayIndex(a, 0);
|
||||
SortArrayByProperty(a, "priority");
|
||||
Log("%v-%d", a, GetLength(a));
|
||||
for (var i = -1; i >= 0; i--)
|
||||
Log("%d", i);
|
||||
}
|
|
@ -2,4 +2,7 @@
|
|||
Title=Power System
|
||||
|
||||
[Landscape]
|
||||
NoScan=1
|
||||
NoScan=1
|
||||
|
||||
[Weather]
|
||||
Wind=0,0,-100,100
|
|
@ -6,6 +6,10 @@
|
|||
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
|
||||
*/
|
||||
|
||||
|
@ -18,8 +22,10 @@ protected func Initialize()
|
|||
|
||||
protected func InitializePlayer(int plr)
|
||||
{
|
||||
// Set zoom and move player to the middle of the scenario.
|
||||
// Set zoom to full map size.
|
||||
SetPlayerZoomByViewRange(plr, LandscapeWidth(), nil, PLRZOOM_Direct);
|
||||
|
||||
// Move player to the start of the scenario.
|
||||
GetCrew(plr)->SetPosition(120, 150);
|
||||
|
||||
// Add test control effect.
|
||||
|
@ -27,7 +33,7 @@ protected func InitializePlayer(int plr)
|
|||
effect.testnr = 1;
|
||||
effect.launched = false;
|
||||
effect.plr = plr;
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
@ -121,47 +127,74 @@ global func Test1_OnStart(int plr)
|
|||
{
|
||||
// Power source: one wind generator.
|
||||
SetWindFixed(50);
|
||||
CreateObjectAbove(WindGenerator, 88, 160, plr);
|
||||
CreateObjectAbove(WindGenerator, 72, 160, plr);
|
||||
|
||||
// Power consumer: one pump.
|
||||
var pump = CreateObjectAbove(Pump, 124, 160, plr);
|
||||
var source = CreateObjectAbove(Pipe, 176, 292, plr);
|
||||
var source_pipe = CreateObjectAbove(PipeLine, 144, 160, plr);
|
||||
source_pipe->SetActionTargets(source, pump);
|
||||
pump->SetSource(source_pipe);
|
||||
var drain = CreateObjectAbove(Pipe, 248, 100, plr);
|
||||
var drain_pipe = CreateObjectAbove(PipeLine, 224, 48, plr);
|
||||
drain_pipe->AddVertex(208, 48);
|
||||
drain_pipe->SetActionTargets(drain, pump);
|
||||
pump->SetDrain(drain_pipe);
|
||||
// Power consumer: one workshop.
|
||||
var workshop = CreateObjectAbove(ToolsWorkshop, 110, 160, plr);
|
||||
workshop->CreateContents(Wood, 2);
|
||||
workshop->CreateContents(Metal, 2);
|
||||
workshop->AddToQueue(Shovel, 2);
|
||||
|
||||
// Log what the test is about.
|
||||
Log("A steady power source (wind generator) supplying a steady power consumer (pump).");
|
||||
Log("A steady power source (wind generator) supplying a steady power consumer (workshop).");
|
||||
return true;
|
||||
}
|
||||
|
||||
global func Test1_Completed()
|
||||
{
|
||||
if (GetMaterial(248, 84) == Material("Water"))
|
||||
if (ObjectCount(Find_ID(Shovel)) >= 2)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
global func Test1_OnFinished()
|
||||
{
|
||||
// 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("Water"))
|
||||
ClearFreeRect(x, y, 1, 1);
|
||||
// Remove wind generator, pump and the pipes.
|
||||
RemoveAll(Find_Or(Find_ID(WindGenerator), Find_ID(Pump), Find_ID(Pipe)));
|
||||
// Remove wind generator, compensator and workshop.
|
||||
RemoveAll(Find_Or(Find_ID(WindGenerator), Find_ID(Compensator), Find_ID(ToolsWorkshop)));
|
||||
return;
|
||||
}
|
||||
|
||||
// Test for one on-demand source and a few consumers.
|
||||
global func Test2_OnStart(int plr)
|
||||
{
|
||||
// Power source: one steam engine.
|
||||
var engine = CreateObjectAbove(SteamEngine, 100, 160, plr);
|
||||
var coal = engine->CreateContents(Coal, 1);
|
||||
coal->SetCon(10);
|
||||
|
||||
// Power consumer: sawmill.
|
||||
CreateObject(Sawmill, 40, 160, plr);
|
||||
for (var i = 0; i < 1; i++)
|
||||
CreateObject(Tree_Coconut, 40, 160)->ChopDown();
|
||||
|
||||
// Power consumer: armory.
|
||||
var armory = CreateObject(Armory, 280, 160, plr);
|
||||
armory->CreateContents(Firestone, 8);
|
||||
armory->CreateContents(Metal, 8);
|
||||
armory->AddToQueue(IronBomb, 8);
|
||||
|
||||
// Log what the test is about.
|
||||
Log("An on-demand power source (steam engine) supplying a few on-demand power consumers (sawmill, armory).");
|
||||
return true;
|
||||
}
|
||||
|
||||
global func Test2_Completed()
|
||||
{
|
||||
// One wood is being burned as fuel by the steam engine: 3 * 4 - 1 = 11.
|
||||
if (ObjectCount(Find_ID(Wood)) >= 3 && ObjectCount(Find_ID(IronBomb)) >= 8)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
global func Test2_OnFinished()
|
||||
{
|
||||
// Remove steam engine, sawmill, armory.
|
||||
RemoveAll(Find_Or(Find_ID(SteamEngine), Find_ID(Sawmill), Find_ID(Armory)));
|
||||
return;
|
||||
}
|
||||
|
||||
// Test for one on-demand source and one steady consumer.
|
||||
global func Test2_OnStart(int plr)
|
||||
global func Test3_OnStart(int plr)
|
||||
{
|
||||
// Power source: one steam engine.
|
||||
var engine = CreateObjectAbove(SteamEngine, 40, 160, plr);
|
||||
|
@ -187,14 +220,14 @@ global func Test2_OnStart(int plr)
|
|||
return true;
|
||||
}
|
||||
|
||||
global func Test2_Completed()
|
||||
global func Test3_Completed()
|
||||
{
|
||||
if (GetMaterial(248, 48) == Material("Water"))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
global func Test2_OnFinished()
|
||||
global func Test3_OnFinished()
|
||||
{
|
||||
// Restore water levels.
|
||||
DrawMaterialQuad("Water", 144, 168, 208 + 1, 168, 208 + 1, 304, 144, 304, true);
|
||||
|
@ -208,7 +241,7 @@ global func Test2_OnFinished()
|
|||
}
|
||||
|
||||
// Test one steady source with one steady consumer and a prioritized on-demand consumer.
|
||||
global func Test3_OnStart(int plr)
|
||||
global func Test4_OnStart(int plr)
|
||||
{
|
||||
// Power source: one wind generator.
|
||||
SetWindFixed(25);
|
||||
|
@ -238,14 +271,14 @@ global func Test3_OnStart(int plr)
|
|||
return true;
|
||||
}
|
||||
|
||||
global func Test3_Completed()
|
||||
global func Test4_Completed()
|
||||
{
|
||||
if (FindObject(Find_ID(ElevatorCase), Find_InRect(372, 230, 40, 40)))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
global func Test3_OnFinished()
|
||||
global func Test4_OnFinished()
|
||||
{
|
||||
// Restore water levels.
|
||||
DrawMaterialQuad("Water", 144, 168, 208 + 1, 168, 208 + 1, 304, 144, 304, true);
|
||||
|
@ -261,7 +294,7 @@ global func Test3_OnFinished()
|
|||
}
|
||||
|
||||
// Basic test for power storage: one steady supplier, one storage and one consumer which needs energy from both sources.
|
||||
global func Test4_OnStart(int plr)
|
||||
global func Test5_OnStart(int plr)
|
||||
{
|
||||
// Power source: one wind generator.
|
||||
SetWindFixed(25);
|
||||
|
@ -281,14 +314,14 @@ global func Test4_OnStart(int plr)
|
|||
return true;
|
||||
}
|
||||
|
||||
global func Test4_Completed()
|
||||
global func Test5_Completed()
|
||||
{
|
||||
if (ObjectCount(Find_ID(Shovel)) >= 2)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
global func Test4_OnFinished()
|
||||
global func Test5_OnFinished()
|
||||
{
|
||||
// Remove wind generator, compensator and workshop.
|
||||
RemoveAll(Find_Or(Find_ID(WindGenerator), Find_ID(Compensator), Find_ID(ToolsWorkshop)));
|
||||
|
@ -296,7 +329,7 @@ global func Test4_OnFinished()
|
|||
}
|
||||
|
||||
// Test one overproducing on-demand producer with power storage and one steady consumer.
|
||||
global func Test5_OnStart(int plr)
|
||||
global func Test6_OnStart(int plr)
|
||||
{
|
||||
// Power source: one steam engine.
|
||||
var engine = CreateObjectAbove(SteamEngine, 40, 160, plr);
|
||||
|
@ -320,38 +353,79 @@ global func Test5_OnStart(int plr)
|
|||
return true;
|
||||
}
|
||||
|
||||
global func Test5_Completed()
|
||||
global func Test6_Completed()
|
||||
{
|
||||
if (ObjectCount(Find_ID(Shovel)) >= 16)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
global func Test5_OnFinished()
|
||||
global func Test6_OnFinished()
|
||||
{
|
||||
// Remove steam engine, compensators and workshop.
|
||||
RemoveAll(Find_Or(Find_ID(SteamEngine), Find_ID(Compensator), Find_ID(ToolsWorkshop)));
|
||||
return;
|
||||
}
|
||||
|
||||
/*-- Helper Functions --*/
|
||||
|
||||
global func RemoveTest()
|
||||
// Test an on-demand producer as back-up for a steady producer with for steady consumers.
|
||||
global func Test7_OnStart(int plr)
|
||||
{
|
||||
// Remove all objects besides the clonk.
|
||||
RemoveAll(Find_Not(Find_OCF(OCF_CrewMember)));
|
||||
// Power source: one steam engine.
|
||||
var engine = CreateObject(SteamEngine, 40, 160, plr);
|
||||
engine->CreateContents(Coal, 1);
|
||||
|
||||
// Remove all effects besides the test control effect.
|
||||
/*var effect;
|
||||
var index = 0;
|
||||
while (effect = GetEffect("*", nil, index))
|
||||
// Power source: wind generators which are turned on and off again due to wind.
|
||||
CreateObject(WindGenerator, 356, 104, plr);
|
||||
SetWindFixed(80);
|
||||
Schedule(nil, "SetWindFixed(0)", 5 * 36);
|
||||
Schedule(nil, "SetWindFixed(80)", 8 * 36);
|
||||
|
||||
// Power connection: flagpole.
|
||||
CreateObject(Flagpole, 328, 132, plr);
|
||||
|
||||
// Power consumer: two pumps.
|
||||
for (var i = 0; i < 2; i++)
|
||||
{
|
||||
Log("%v", effect);
|
||||
index++;
|
||||
}*/
|
||||
var pump = CreateObject(Pump, 92 + i * 20, 160, plr);
|
||||
var source = CreateObject(Pipe, 176, 292, plr);
|
||||
var source_pipe = CreateObject(PipeLine, 144, 160, plr);
|
||||
source_pipe->SetActionTargets(source, pump);
|
||||
pump->SetSource(source_pipe);
|
||||
var drain = CreateObject(Pipe, 248, 100, plr);
|
||||
var drain_pipe = CreateObject(PipeLine, 224, 48, plr);
|
||||
drain_pipe->AddVertex(208, 48);
|
||||
drain_pipe->SetActionTargets(drain, pump);
|
||||
pump->SetDrain(drain_pipe);
|
||||
}
|
||||
|
||||
// Log what the test is about.
|
||||
Log("An on-demand producer (steam engine) as back-up for a steady producer (wind generator) with for steady consumers (pumps).");
|
||||
return true;
|
||||
}
|
||||
|
||||
global func Test7_Completed()
|
||||
{
|
||||
if (GetMaterial(248, 48) == Material("Water"))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
global func Test7_OnFinished()
|
||||
{
|
||||
// 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("Water"))
|
||||
ClearFreeRect(x, y, 1, 1);
|
||||
// Remove steam engine, wind generator, flagpole, pump and the pipes.
|
||||
RemoveAll(Find_Or(Find_ID(SteamEngine), Find_ID(WindGenerator), Find_ID(Flagpole), Find_ID(Pump), Find_ID(Pipe)));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*-- Helper Functions --*/
|
||||
|
||||
global func SetWindFixed(int strength)
|
||||
{
|
||||
strength = BoundBy(strength, -100, 100);
|
||||
|
|
Loading…
Reference in New Issue