forked from Mirrors/openclonk
243 lines
5.0 KiB
C
243 lines
5.0 KiB
C
/**
|
|
ConstructionSite
|
|
Needs material put into it, then constructs the set building.
|
|
|
|
@author boni
|
|
*/
|
|
|
|
local definition;
|
|
local direction;
|
|
local stick_to;
|
|
local full_material; // true when all needed material is in the site
|
|
|
|
public func IsContainer() { return !full_material; }
|
|
// disallow taking stuff out
|
|
public func RefuseTransfer(object toMove) { return true; }
|
|
|
|
// we have 2 interaction modes
|
|
public func IsInteractable(object obj) { return definition != nil && !full_material; }
|
|
public func GetInteractionCount() { return 2; }
|
|
public func GetInteractionMetaInfo(object obj, int num)
|
|
{
|
|
if(num == 0)
|
|
return {IconName=nil, IconID=Hammer, Description="$TxtTransfer$"};
|
|
if(num == 1)
|
|
return {IconName=nil, IconID=Icon_Cancel, Description="$TxtAbort$"};
|
|
}
|
|
|
|
public func Construction()
|
|
{
|
|
this.visibility = VIS_None;
|
|
definition = nil;
|
|
full_material = false;
|
|
|
|
return true;
|
|
}
|
|
|
|
public func Set(id def, int dir, object stick)
|
|
{
|
|
definition = def;
|
|
direction = dir;
|
|
stick_to = stick;
|
|
|
|
var xw = (1-dir*2)*1000;
|
|
|
|
var w,h;
|
|
w = def->GetDefWidth();
|
|
h = def->GetDefHeight();
|
|
|
|
SetGraphics(nil, def, 1, GFXOV_MODE_Base);
|
|
SetClrModulation(RGBa(255,255,255,50), 1);
|
|
SetObjDrawTransform(xw,0,0,0,1000, -h*500,1);
|
|
SetGraphics(nil, def, 2, GFXOV_MODE_Base, nil, GFX_BLIT_Wireframe);
|
|
SetObjDrawTransform(xw,0,0,0,1000, -h*500,2);
|
|
SetShape(-w/2, -h, w, h);
|
|
|
|
SetName(Translate(Format("TxtConstruction",def->GetName())));
|
|
|
|
this.visibility = VIS_Owner | VIS_Allies;
|
|
|
|
ShowMissingComponents();
|
|
}
|
|
|
|
// Scenario saving
|
|
func SaveScenarioObject(props)
|
|
{
|
|
if (!inherited(props, ...)) return false;
|
|
props->Remove("Name");
|
|
if (definition) props->AddCall("Definition", this, "Set", definition, direction, stick_to);
|
|
return true;
|
|
}
|
|
|
|
// only allow collection if needed
|
|
public func RejectCollect(id def, object obj)
|
|
{
|
|
var max = GetComponent(def, nil, nil, definition);
|
|
|
|
// not a component?
|
|
if(max == 0)
|
|
return true;
|
|
if(ContentsCount(def) < max)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
// check if full
|
|
public func Collection2(object obj)
|
|
{
|
|
// update message
|
|
ShowMissingComponents();
|
|
|
|
// check if we're done?
|
|
if(full_material)
|
|
StartConstructing();
|
|
}
|
|
|
|
// Interacting removes the Construction site
|
|
public func Interact(object clonk, int num)
|
|
{
|
|
// Open Contents-Menu
|
|
if(num == 0)
|
|
{
|
|
clonk->CreateContentsMenus();
|
|
}
|
|
// Remove Site
|
|
if(num == 1)
|
|
{
|
|
// test
|
|
for(var obj in FindObjects(Find_Container(this)))
|
|
obj->Exit();
|
|
|
|
RemoveObject();
|
|
}
|
|
}
|
|
|
|
private func ShowMissingComponents()
|
|
{
|
|
if(definition == nil)
|
|
{
|
|
Message("");
|
|
return;
|
|
}
|
|
|
|
var stuff = GetMissingComponents();
|
|
//var msg = "Construction Needs:";
|
|
var msg = "@";
|
|
for(var s in stuff)
|
|
if(s.count > 0)
|
|
msg = Format("%s %dx{{%i}}", msg, s.count, s.id);
|
|
|
|
//Message("@%s",msg);
|
|
CustomMessage(msg, this, NO_OWNER, 0, 23);
|
|
}
|
|
|
|
private func GetMissingComponents()
|
|
{
|
|
if(definition == nil)
|
|
return;
|
|
|
|
if(full_material == true)
|
|
return nil;
|
|
|
|
// set false again as soon as we find a missing component
|
|
full_material = true;
|
|
|
|
// check for material
|
|
var comp, index = 0;
|
|
var missing_material = CreateArray();
|
|
while (comp = GetComponent(nil, index, nil, definition))
|
|
{
|
|
// find material
|
|
var max_amount = GetComponent(comp, nil, nil, definition);
|
|
var c = ContentsCount(comp);
|
|
var dif = max_amount-c;
|
|
|
|
if(dif > 0)
|
|
{
|
|
PushBack(missing_material, {id=comp, count=dif});
|
|
full_material = false;
|
|
}
|
|
|
|
index++;
|
|
}
|
|
|
|
return missing_material;
|
|
}
|
|
|
|
private func StartConstructing()
|
|
{
|
|
if(!definition)
|
|
return;
|
|
if(!full_material)
|
|
return;
|
|
|
|
// find all objects on the bottom of the area that are not stuck
|
|
var wdt = GetObjWidth();
|
|
var hgt = GetObjHeight();
|
|
var lying_around = FindObjects(Find_Or(Find_Category(C4D_Vehicle), Find_Category(C4D_Object), Find_Category(C4D_Living)),Find_InRect(-wdt/2 - 2, -hgt, wdt + 2, hgt + 12), Find_OCF(OCF_InFree));
|
|
|
|
// create the construction
|
|
var site;
|
|
if(!(site = CreateConstruction(definition, 0, 0, GetOwner(), 1, 1, 1)))
|
|
{
|
|
// spit out error message. This could happen if the landscape changed in the meantime
|
|
// a little hack: the message would immediately vanish because this object is deleted. So, instead display the
|
|
// message on one of the contents.
|
|
if(Contents(0))
|
|
CustomMessage("$TxtNoConstructionHere$", Contents(0), GetOwner(), nil,nil, RGB(255,0,0));
|
|
Interact(nil, 1);
|
|
return;
|
|
}
|
|
|
|
if(direction)
|
|
site->SetDir(direction);
|
|
// Inform about sticky building
|
|
if (stick_to)
|
|
site->CombineWith(stick_to);
|
|
|
|
// Autoconstruct 2.0!
|
|
Schedule(site, "DoCon(2)",1,50);
|
|
Schedule(this,"RemoveObject()",1);
|
|
|
|
// clean up stuck objects
|
|
for(var o in lying_around)
|
|
{
|
|
var x, y;
|
|
var dif = 0;
|
|
|
|
x = o->GetX();
|
|
y = o->GetY();
|
|
|
|
// move living creatures upwards till they stand on top.
|
|
if(o->GetOCF() & OCF_Alive)
|
|
{
|
|
while(o->GetContact(-1, CNAT_Bottom))
|
|
{
|
|
// only up to 20 pixel
|
|
if(dif > 20)
|
|
{
|
|
o->SetPosition(x,y);
|
|
break;
|
|
}
|
|
|
|
dif++;
|
|
o->SetPosition(x, y-dif);
|
|
}
|
|
}
|
|
else {
|
|
while(o->Stuck())
|
|
{
|
|
// only up to 20 pixel
|
|
if(dif > 20)
|
|
{
|
|
o->SetPosition(x,y);
|
|
break;
|
|
}
|
|
|
|
dif++;
|
|
o->SetPosition(x, y-dif);
|
|
}
|
|
}
|
|
}
|
|
} |