forked from Mirrors/openclonk
163 lines
3.9 KiB
C
163 lines
3.9 KiB
C
/**
|
|
Expansion
|
|
A certain amount of the map must be claimed by constructing flags.
|
|
This is tested by a Monte Carlo simulation over the whole map,
|
|
checking whether the point is covered by a flagpole.
|
|
|
|
@author Maikel
|
|
*/
|
|
|
|
#include Library_Goal
|
|
|
|
|
|
local expansion_goal;
|
|
local mc_data;
|
|
|
|
protected func Initialize()
|
|
{
|
|
expansion_goal = 0;
|
|
// Start running the monte carlo simulation.
|
|
mc_data = [];
|
|
AddEffect("IntAreaMonteCarlo", this, 100, 1, this);
|
|
return inherited(...);
|
|
}
|
|
|
|
// Set the expansion goal in promillage of the total map.
|
|
public func SetExpansionGoal(int exp_area)
|
|
{
|
|
expansion_goal = exp_area;
|
|
return;
|
|
}
|
|
|
|
// Returns the expansion goal in promillage of the total map.
|
|
public func GetExpansionGoal()
|
|
{
|
|
return expansion_goal;
|
|
}
|
|
|
|
// Scenario saving
|
|
public func SaveScenarioObject(props)
|
|
{
|
|
if (!inherited(props, ...)) return false;
|
|
if (expansion_goal) props->AddCall("Goal", this, "SetExpansionGoal", expansion_goal);
|
|
return true;
|
|
}
|
|
|
|
/*-- Goal interface --*/
|
|
|
|
// The goal is fulfilled if the expansio goal is covered by flags.
|
|
public func IsFulfilled()
|
|
{
|
|
// Check if goal is fulfilled.
|
|
if (GetExpansionArea() >= GetExpansionGoal())
|
|
return true;
|
|
// Not yet fulfilled.
|
|
return false;
|
|
}
|
|
|
|
// Returns the promillage of the total map covered by flags.
|
|
private func GetExpansionArea()
|
|
{
|
|
// Evaluate mc simulation.
|
|
var area = 0, cnt = 0;
|
|
for (var mc in mc_data)
|
|
{
|
|
if (mc != nil)
|
|
{
|
|
area += mc;
|
|
cnt++;
|
|
}
|
|
}
|
|
if (!cnt)
|
|
return 0;
|
|
return area / cnt;
|
|
}
|
|
|
|
// Monte Carlo simulation to determine the area covered by flagpoles.
|
|
// There is thin balance between the accuracy of the simulation, the
|
|
// number of simulations per frame and the refresh rate of the data,
|
|
// or equivalently how long past data is stored.
|
|
private func FxIntAreaMonteCarloTimer()
|
|
{
|
|
// Perform simulations and store them.
|
|
var cnt = 40; // Perform 40 simulations per frame.
|
|
var store = 500; // Store last 500 events.
|
|
var rate = 0;
|
|
for (var i = 0; i < cnt; i++)
|
|
{
|
|
var x = Random(LandscapeWidth());
|
|
var y = Random(LandscapeHeight());
|
|
if (CoveredByFlag(x, y))
|
|
rate++;
|
|
}
|
|
var promille = 1000 * rate / cnt;
|
|
// Add new montecarlo data to the end the data list and remove old entry.
|
|
for (var i = 0; i < store - 1; i++)
|
|
{
|
|
mc_data[i] = mc_data[i+1];
|
|
}
|
|
mc_data[store - 1] = promille;
|
|
return;
|
|
}
|
|
|
|
// Returns whether the point (x,y) is covered by a flagpole.
|
|
private func CoveredByFlag(int x, int y)
|
|
{
|
|
for (var flag in FindObjects(Find_Func("IsFlagpole"), Sort_Distance(x - GetX(), y - GetY())))
|
|
if (Distance(flag->GetX(), flag->GetY(), x, y) < flag->GetFlagRadius())
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
// Return the description of this goal.
|
|
public func GetDescription(int plr)
|
|
{
|
|
var message;
|
|
if (GetExpansionArea() >= GetExpansionGoal() || GetExpansionGoal() == 0)
|
|
message = Format("$MsgGoalFulfilled$");
|
|
else
|
|
message = Format("$MsgGoalUnFulfilled$", 100 * GetExpansionArea() / GetExpansionGoal());
|
|
return message;
|
|
}
|
|
|
|
// Shows or hides a message window with information.
|
|
public func Activate(int plr)
|
|
{
|
|
// If goal message open -> hide it.
|
|
if (GetEffect("GoalMessage", this))
|
|
{
|
|
CustomMessage("", nil, plr, nil, nil, nil, nil, nil, MSG_HCenter);
|
|
RemoveEffect("GoalMessage", this);
|
|
return;
|
|
}
|
|
// Otherwise open a new message.
|
|
AddEffect("GoalMessage", this, 100, 0, this);
|
|
var message;
|
|
if (GetExpansionArea() >= GetExpansionGoal() || GetExpansionGoal() == 0)
|
|
message = Format("@$MsgGoalFulfilled$");
|
|
else
|
|
message = Format("@$MsgGoalUnFulfilled$", 100 * GetExpansionArea() / GetExpansionGoal());
|
|
|
|
CustomMessage(message, nil, plr, 0, 16 + 64, 0xffffff, GUI_MenuDeco, this, MSG_HCenter);
|
|
return;
|
|
}
|
|
|
|
protected func FxGoalMessageStart() {}
|
|
|
|
public func GetShortDescription(int plr)
|
|
{
|
|
// Show expansion percentage.
|
|
var perc = 0;
|
|
if (GetExpansionGoal())
|
|
perc = Min(100, 100 * GetExpansionArea() / GetExpansionGoal());
|
|
var clr = RGB(255, 0, 0);
|
|
if (perc >= 100)
|
|
clr = RGB(0, 255, 0);
|
|
var msg = Format("<c %x>%d%</c>", clr, perc);
|
|
return msg;
|
|
}
|
|
|
|
/*-- Proplist --*/
|
|
|
|
local Name = "$Name$";
|