forked from Mirrors/openclonk
Basements combine in all four directions when constructing!
parent
ad2bbbf5fd
commit
f4ca4466f1
|
@ -8,6 +8,7 @@
|
|||
static const CONSTRUCTION_STICK_Left = 1;
|
||||
static const CONSTRUCTION_STICK_Right = 2;
|
||||
static const CONSTRUCTION_STICK_Bottom = 4;
|
||||
static const CONSTRUCTION_STICK_Top = 8;
|
||||
|
||||
local extra_overlay, dimension_x, dimension_y, clonk, structure, direction, stick_to, blocked;
|
||||
local GFX_StructureOverlay = 1;
|
||||
|
@ -110,47 +111,118 @@ public func AdjustPreview(bool below_surface, bool look_up, bool no_call)
|
|||
// x and y are refined mouse coordinates so always centered at the clonk
|
||||
func Reposition(int x, int y)
|
||||
{
|
||||
x = BoundBy(x, -dimension_x/2, dimension_x/2);
|
||||
y = BoundBy(y, -dimension_y/2, dimension_y/2);
|
||||
var clonk_width = clonk->GetObjWidth();
|
||||
var clonk_height = clonk->GetObjHeight();
|
||||
x = BoundBy(x, -dimension_x - clonk_width/2, dimension_x + clonk_width/2);
|
||||
y = BoundBy(y, -dimension_y - clonk_height/2, dimension_y + clonk_height/2);
|
||||
// Try to combine the structure with other structures.
|
||||
var found = false;
|
||||
if (structure->~ConstructionCombineWith())
|
||||
{
|
||||
var stick_dir = structure->~ConstructionCombineDirection();
|
||||
var find_rect = Find_InRect(AbsX(clonk->GetX() + x - dimension_x/2 - 10), AbsY(clonk->GetY() + y - dimension_y/2 - 10), dimension_x + 20, dimension_y + 20);
|
||||
if ((stick_dir & CONSTRUCTION_STICK_Bottom))
|
||||
find_rect = Find_AtPoint(AbsX(clonk->GetX() + x), AbsY(clonk->GetY() + y));
|
||||
var other = FindObject(Find_Func(structure->ConstructionCombineWith(), this),
|
||||
find_rect,
|
||||
Find_OCF(OCF_Fullcon),
|
||||
Find_Layer(clonk->GetObjectLayer()),
|
||||
Find_Allied(clonk->GetOwner()),
|
||||
Find_NoContainer());
|
||||
if (other)
|
||||
// There is no use in doing all the other checks if no sticking direction is defined at all
|
||||
// That's just wrong use of ConstructionCombineWith
|
||||
if (structure->~ConstructionCombineDirection())
|
||||
{
|
||||
x = other->GetX();
|
||||
y = other->GetY();
|
||||
// Combine to different directions.
|
||||
if ((stick_dir & CONSTRUCTION_STICK_Left) && other->GetX() >= GetX())
|
||||
x = other->GetX() - other->GetObjWidth()/2 - dimension_x / 2;
|
||||
if ((stick_dir & CONSTRUCTION_STICK_Right) && other->GetX() < GetX())
|
||||
x = other->GetX() + other->GetObjWidth()/2 + dimension_x / 2;
|
||||
if ((stick_dir & CONSTRUCTION_STICK_Bottom))
|
||||
y = other->GetY() + other->GetObjHeight()/2 + dimension_y / 2;
|
||||
// Add an additional offset if needed, for example a basement can be place
|
||||
// only under a part of the structure.
|
||||
var stick_offset = structure->~ConstructionCombineOffset(other);
|
||||
if (stick_offset)
|
||||
//var find_rect = Find_InRect(AbsX(clonk->GetX() + x - dimension_x/2 - 10), AbsY(clonk->GetY() + y - dimension_y/2 - 10), dimension_x + 20, dimension_y + 20);
|
||||
//if ((stick_dir & CONSTRUCTION_STICK_Bottom))
|
||||
|
||||
var find_rect = Find_AtPoint(clonk->GetX() - GetX() + x, clonk->GetY() - GetY() + y);
|
||||
|
||||
var other = FindObject(Find_Func(structure->ConstructionCombineWith(), this),
|
||||
find_rect,
|
||||
Find_OCF(OCF_Fullcon),
|
||||
Find_Layer(clonk->GetObjectLayer()),
|
||||
Find_Allied(clonk->GetOwner()),
|
||||
Find_NoContainer());
|
||||
|
||||
if (other)
|
||||
{
|
||||
x += stick_offset[0];
|
||||
y += stick_offset[1];
|
||||
var stick_dir = structure->ConstructionCombineDirection(other);
|
||||
var other_width = other->GetObjWidth();
|
||||
var other_height = other->GetObjHeight();
|
||||
// Determine the position from the other object's center currently hovered
|
||||
var other_offset_x = clonk->GetX() + x - other->GetX();
|
||||
var other_offset_y = clonk->GetY() + y - other->GetY();
|
||||
|
||||
// The tricky part is now to determine which of the four possible directions should be used
|
||||
// The shape of the 'other' is divided like this (* is center):
|
||||
// __________________________
|
||||
// | | Top | |
|
||||
// | Left |----*----| Right |
|
||||
// |_______|_Bottom__|_______|
|
||||
//
|
||||
// Whichever part is howered on is checked first for stick direction
|
||||
|
||||
// Hopefully, in the end this contains a single sticking direction.
|
||||
var single_stick_to = 0;
|
||||
|
||||
// Left
|
||||
if (other_offset_x < other_width / -6)
|
||||
{
|
||||
single_stick_to = GetStickingDirection(stick_dir, CONSTRUCTION_STICK_Left, CONSTRUCTION_STICK_Bottom, CONSTRUCTION_STICK_Top, CONSTRUCTION_STICK_Right, other_offset_y, 0);
|
||||
}
|
||||
// Right
|
||||
else if (other_offset_x > other_width / 6)
|
||||
{
|
||||
single_stick_to = GetStickingDirection(stick_dir, CONSTRUCTION_STICK_Right, CONSTRUCTION_STICK_Bottom, CONSTRUCTION_STICK_Top, CONSTRUCTION_STICK_Left, other_offset_y, 0);
|
||||
}
|
||||
// Bottom
|
||||
else if (other_offset_y >= 0)
|
||||
{
|
||||
single_stick_to = GetStickingDirection(stick_dir, CONSTRUCTION_STICK_Bottom, CONSTRUCTION_STICK_Right, CONSTRUCTION_STICK_Left, CONSTRUCTION_STICK_Top, other_offset_x, 0);
|
||||
}
|
||||
// Top
|
||||
else if (other_offset_y < 0)
|
||||
{
|
||||
single_stick_to = GetStickingDirection(stick_dir, CONSTRUCTION_STICK_Top, CONSTRUCTION_STICK_Right, CONSTRUCTION_STICK_Left, CONSTRUCTION_STICK_Bottom, other_offset_x, 0);
|
||||
}
|
||||
|
||||
// If no direction is found, something went wrong.
|
||||
// Probably ConstructionCombineDirection() returned garbage.
|
||||
if (single_stick_to)
|
||||
{
|
||||
if (single_stick_to == CONSTRUCTION_STICK_Left)
|
||||
{
|
||||
x = other->GetX() - other_width/2 - dimension_x/2;
|
||||
y = other->GetY();
|
||||
}
|
||||
if (single_stick_to == CONSTRUCTION_STICK_Right)
|
||||
{
|
||||
x = other->GetX() + other_width/2 + dimension_x/2;
|
||||
y = other->GetY();
|
||||
}
|
||||
if (single_stick_to == CONSTRUCTION_STICK_Bottom)
|
||||
{
|
||||
x = other->GetX();
|
||||
y = other->GetY() + other_height/2 + dimension_y/2;
|
||||
}
|
||||
if (single_stick_to == CONSTRUCTION_STICK_Top)
|
||||
{
|
||||
x = other->GetX();
|
||||
y = other->GetY() - other_height/2 - dimension_y/2;
|
||||
}
|
||||
// Add an additional offset if needed, for example a basement can be place
|
||||
// only under a part of the structure.
|
||||
var stick_offset = structure->~ConstructionCombineOffset(other, single_stick_to);
|
||||
if (stick_offset)
|
||||
{
|
||||
x += stick_offset[0];
|
||||
y += stick_offset[1];
|
||||
}
|
||||
// Save the other building for use in AdjustPreview and for color changing
|
||||
stick_to = other;
|
||||
// Found another building and a way to stick to it!
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
stick_to = other;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
// Narrow the distance a construction site can be built around the clonk
|
||||
x = BoundBy(x, -dimension_x/2 - clonk_width/2, dimension_x/2 + clonk_width/2);
|
||||
y = BoundBy(y, -dimension_y/2 - clonk_height/2, dimension_y/2 + clonk_height/2);
|
||||
x = clonk->GetX() + x;
|
||||
y = clonk->GetY() + y;
|
||||
}
|
||||
|
@ -163,11 +235,14 @@ func Reposition(int x, int y)
|
|||
else if (stick_to)
|
||||
{
|
||||
SetGraphics(nil, ConstructionPreviewer_IconCombine, GFX_CombineIconOverlay, GFXOV_MODE_Base);
|
||||
var dir = 1;
|
||||
if (stick_to->GetX() < GetX()) dir = -1;
|
||||
if (structure->~CombineToBottom())
|
||||
dir = 0;
|
||||
SetObjDrawTransform(1000, 0, dimension_x/2 * 1000 * dir, 0, 1000, 0, GFX_CombineIconOverlay);
|
||||
var x_dir = 1, y_dir = 1;
|
||||
if (stick_to->GetX() < GetX()) x_dir = -1;
|
||||
if (stick_to->GetY() < GetY()) y_dir = -1;
|
||||
if (single_stick_to == CONSTRUCTION_STICK_Bottom || single_stick_to == CONSTRUCTION_STICK_Top)
|
||||
x_dir = 0;
|
||||
if (single_stick_to == CONSTRUCTION_STICK_Left || single_stick_to == CONSTRUCTION_STICK_Right)
|
||||
y_dir = 0;
|
||||
SetObjDrawTransform(1000, 0, dimension_x/2 * 1000 * x_dir, 0, 1000, dimension_y/2 * 1000 * y_dir, GFX_CombineIconOverlay);
|
||||
}
|
||||
// Update the extra overlay possibly added to the preview.
|
||||
extra_overlay = structure->~ConstructionPreview(this, GFX_PreviewerPictureOverlay, direction);
|
||||
|
@ -177,6 +252,47 @@ func Reposition(int x, int y)
|
|||
AdjustPreview(structure->~IsBelowSurfaceConstruction());
|
||||
}
|
||||
|
||||
// Helper function to return a definite sticking direction.
|
||||
// Used whenever the cursor hovers the 'left' or 'right' part of the other building.
|
||||
// See Reposition() to see an example of the four parts.
|
||||
func GetStickingDirection(int stick_dir, int primary_dir, int secondary_dir, int tertiary_dir, int fourth_dir, int cursor_coord, int other_coord)
|
||||
{
|
||||
// If the primary direction is in stick_dir, we're done
|
||||
if (stick_dir & primary_dir)
|
||||
{
|
||||
return primary_dir;
|
||||
}
|
||||
// Afterwards check second / third directions
|
||||
else if (stick_dir & secondary_dir || stick_dir & tertiary_dir)
|
||||
{
|
||||
// If one of those isn't in stick_dir, no coordinate checking is necessary
|
||||
if (!(stick_dir & tertiary_dir))
|
||||
{
|
||||
return secondary_dir;
|
||||
}
|
||||
else if (!(stick_dir & secondary_dir))
|
||||
{
|
||||
return tertiary_dir;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Coordinates have to be checked
|
||||
// secondary always is one pixel better than tertiary
|
||||
if (cursor_coord >= other_coord)
|
||||
return secondary_dir;
|
||||
else
|
||||
return tertiary_dir;
|
||||
}
|
||||
}
|
||||
// Fourth direction is returned last but no other directions takes the point
|
||||
else if (stick_dir & fourth_dir)
|
||||
{
|
||||
return fourth_dir;
|
||||
}
|
||||
// If this happens, something is wrong
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Flips the preview horizontally
|
||||
func Flip()
|
||||
{
|
||||
|
@ -196,4 +312,6 @@ func Flip()
|
|||
}
|
||||
|
||||
// UI not saved.
|
||||
func SaveScenarioObject() { return false; }
|
||||
func SaveScenarioObject() { return false; }
|
||||
|
||||
local Plane = 210;
|
|
@ -2,7 +2,7 @@
|
|||
Basement
|
||||
Provides basements to structures, but can also be built as a single object.
|
||||
|
||||
@author Maikel
|
||||
@author: Maikel
|
||||
*/
|
||||
|
||||
#include Library_Structure
|
||||
|
@ -10,16 +10,14 @@
|
|||
local parent;
|
||||
local width;
|
||||
|
||||
protected func Construction()
|
||||
func Construction()
|
||||
{
|
||||
// Make sure the basement does not move while constructing.
|
||||
SetCategory(C4D_StaticBack);
|
||||
return _inherited(...);
|
||||
}
|
||||
|
||||
public func IsHammerBuildable() { return true; }
|
||||
|
||||
protected func Initialize()
|
||||
func Initialize()
|
||||
{
|
||||
var wdt = GetObjWidth();
|
||||
if (parent)
|
||||
|
@ -34,7 +32,7 @@ protected func Initialize()
|
|||
return _inherited(...);
|
||||
}
|
||||
|
||||
protected func Destruction()
|
||||
func Destruction()
|
||||
{
|
||||
// Cast a single rock.
|
||||
CastObjects(Rock, 1, 15, 0, -5);
|
||||
|
@ -53,13 +51,6 @@ public func SetWidth(int wdt)
|
|||
|
||||
public func GetWidth() { return width; }
|
||||
|
||||
// Set the parent if the basement is attached to a structure.
|
||||
public func CombineWith(object stick_to)
|
||||
{
|
||||
SetParent(stick_to);
|
||||
return;
|
||||
}
|
||||
|
||||
public func SetParent(object to_parent)
|
||||
{
|
||||
parent = to_parent;
|
||||
|
@ -74,12 +65,48 @@ public func SetParent(object to_parent)
|
|||
|
||||
public func GetParent() { return parent; }
|
||||
|
||||
/*-- Saving --*/
|
||||
|
||||
public func SaveScenarioObject(proplist props)
|
||||
{
|
||||
if (!inherited(props, ...))
|
||||
return false;
|
||||
if (parent)
|
||||
props->AddCall("BasementParent", this, "SetParent", parent);
|
||||
else if (width != GetObjWidth())
|
||||
props->AddCall("BasementWidth", this, "SetWidth", width);
|
||||
props->Remove("Category");
|
||||
return true;
|
||||
}
|
||||
|
||||
/*-- Construction --*/
|
||||
|
||||
public func IsHammerBuildable() { return true; }
|
||||
// It should not be a structure.
|
||||
public func IsStructure() { return false; }
|
||||
// But a basement!
|
||||
public func IsBasement() { return true; }
|
||||
|
||||
// Is a construction that is built just below the surface.
|
||||
public func IsBelowSurfaceConstruction() { return true; }
|
||||
|
||||
// Sticking to other structures, at the bottom of that structure.
|
||||
// This makes it possible to combine basements with each other.
|
||||
public func IsStructureWithoutBasement() { return true; }
|
||||
|
||||
// Sticking to other structures.
|
||||
|
||||
public func ConstructionCombineWith() { return "IsStructureWithoutBasement"; }
|
||||
public func ConstructionCombineDirection() { return CONSTRUCTION_STICK_Bottom; }
|
||||
|
||||
public func ConstructionCombineDirection(object other)
|
||||
{
|
||||
// All directions are possible for other basements
|
||||
if (other && other->~IsBasement())
|
||||
return CONSTRUCTION_STICK_Left | CONSTRUCTION_STICK_Right | CONSTRUCTION_STICK_Bottom | CONSTRUCTION_STICK_Top;
|
||||
|
||||
// For everything else, the basement is below.
|
||||
return CONSTRUCTION_STICK_Bottom;
|
||||
}
|
||||
|
||||
public func ConstructionCombineOffset(object other)
|
||||
{
|
||||
// Some structures like the elevator require the basement to have an offset.
|
||||
|
@ -90,9 +117,10 @@ public func NoConstructionFlip() { return true; }
|
|||
|
||||
public func AlternativeConstructionPreview(object previewer, int direction, object combine_with)
|
||||
{
|
||||
if (combine_with && combine_with->~IsBasement()) return;
|
||||
|
||||
var wdt = GetSiteWidth(direction, combine_with);
|
||||
previewer->SetObjDrawTransform(1000 * wdt / 40, 0, 0, 0, 1000, 0, previewer.GFX_StructureOverlay);
|
||||
return;
|
||||
}
|
||||
|
||||
public func GetSiteWidth(int direction, object combine_with)
|
||||
|
@ -109,6 +137,8 @@ public func GetSiteWidth(int direction, object combine_with)
|
|||
|
||||
public func SetConstructionSiteOverlay(object site, int direction, object combine_with)
|
||||
{
|
||||
if (combine_with && combine_with->~IsBasement()) return;
|
||||
|
||||
var wdt = GetSiteWidth(direction, combine_with);
|
||||
site->SetGraphics(nil, Basement, 1, GFXOV_MODE_Base);
|
||||
site->SetClrModulation(RGBa(255, 255, 255, 128), 1);
|
||||
|
@ -116,26 +146,15 @@ public func SetConstructionSiteOverlay(object site, int direction, object combin
|
|||
return true;
|
||||
}
|
||||
|
||||
// Don't stick to itself, so it should not be a structure.
|
||||
public func IsStructure() { return false; }
|
||||
|
||||
|
||||
/*-- Saving --*/
|
||||
|
||||
public func SaveScenarioObject(proplist props)
|
||||
// Set the parent if the basement is attached to a structure.
|
||||
public func CombineWith(object stick_to)
|
||||
{
|
||||
if (!inherited(props, ...))
|
||||
return false;
|
||||
if (parent)
|
||||
props->AddCall("BasementParent", this, "SetParent", parent);
|
||||
else if (width != GetObjWidth())
|
||||
props->AddCall("BasementWidth", this, "SetWidth", width);
|
||||
props->Remove("Category");
|
||||
return true;
|
||||
if (stick_to && stick_to->~IsBasement()) return;
|
||||
|
||||
SetParent(stick_to);
|
||||
}
|
||||
|
||||
|
||||
/*-- Proplist --*/
|
||||
/*-- Properties --*/
|
||||
|
||||
local Name = "$Name$";
|
||||
local Description ="$Description$";
|
||||
|
|
|
@ -227,11 +227,19 @@ public func ConstructionPreview(object previewer, int overlay, int dir)
|
|||
}
|
||||
|
||||
// Sticking to other elevators
|
||||
public func ConstructionCombineWith() { return "IsElevator"; }
|
||||
public func ConstructionCombineDirection() { return CONSTRUCTION_STICK_Left | CONSTRUCTION_STICK_Right; }
|
||||
public func ConstructionCombineWith() { return "CanCombineElevator"; }
|
||||
public func ConstructionCombineDirection(object other)
|
||||
{
|
||||
if (!other) return CONSTRUCTION_STICK_Left | CONSTRUCTION_STICK_Right;
|
||||
|
||||
// Only combine when facing correctly
|
||||
if (other->GetDir() == DIR_Left)
|
||||
return CONSTRUCTION_STICK_Right;
|
||||
return CONSTRUCTION_STICK_Left;
|
||||
}
|
||||
|
||||
// Called to determine if sticking is possible
|
||||
public func IsElevator(object previewer)
|
||||
public func CanCombineElevator(object previewer)
|
||||
{
|
||||
if (!previewer) return true;
|
||||
|
||||
|
|
Loading…
Reference in New Issue