forked from Mirrors/openclonk
367 lines
8.5 KiB
C
367 lines
8.5 KiB
C
/*--
|
|
Commits.c
|
|
Authors: flgr, Joern, Tyron, Newton, Ringwaul, Sven2, Maikel
|
|
|
|
Useful user committed functions, this should really be organized into more sensible categories.
|
|
--*/
|
|
|
|
|
|
// Returns the offset to x.
|
|
global func AbsX(int x)
|
|
{
|
|
return x - GetX();
|
|
}
|
|
|
|
// Returns the offset to y.
|
|
global func AbsY(int y)
|
|
{
|
|
return y - GetY();
|
|
}
|
|
|
|
// Supports negative values, and can deliver random values between two bounds.
|
|
global func RandomX(int start, int end)
|
|
{
|
|
var swap;
|
|
// Values swapped: reswap them.
|
|
if (start > end)
|
|
{
|
|
swap = start;
|
|
start = end;
|
|
end = swap;
|
|
}
|
|
// Return random factor.
|
|
return Random(end - start + 1) + start;
|
|
}
|
|
|
|
// Tangens.
|
|
global func Tan(int angle, int radius, int prec)
|
|
{
|
|
return radius * Sin(angle, radius * 100, prec) / Cos(angle, radius * 100, prec);
|
|
}
|
|
|
|
global func Normalize(int angle, int start, int precision)
|
|
{
|
|
if (!precision)
|
|
precision = 1;
|
|
var end = precision * 360 + start;
|
|
|
|
while (angle < start)
|
|
angle += precision * 360;
|
|
while (angle >= end)
|
|
angle -= precision * 360;
|
|
|
|
return angle;
|
|
}
|
|
|
|
// Does not set the speed of an object. But you can set two components of the velocity vector with this function.
|
|
global func SetSpeed(int x_dir, int y_dir, int prec)
|
|
{
|
|
SetXDir(x_dir, prec);
|
|
SetYDir(y_dir, prec);
|
|
return;
|
|
}
|
|
|
|
// Sets an objects's speed and its direction, doesn't it?
|
|
global func SetVelocity(int angle, int speed, int precAng, int precSpd)
|
|
{
|
|
if(!precAng) precAng = 1;
|
|
var x_dir = Sin(angle, speed, precAng);
|
|
var y_dir = -Cos(angle, speed, precAng);
|
|
|
|
SetXDir(x_dir, precSpd);
|
|
SetYDir(y_dir, precSpd);
|
|
return;
|
|
}
|
|
|
|
// Sets the completion of this to new_con.
|
|
global func SetCon(int new_con)
|
|
{
|
|
return DoCon(new_con - GetCon());
|
|
}
|
|
|
|
// Adds value to the account of iPlayer.
|
|
global func DoWealth(int plr, int value)
|
|
{
|
|
return SetWealth(plr, value + GetWealth(plr));
|
|
}
|
|
|
|
// Sets both the X and Y-coordinate of one vertex.
|
|
global func SetVertexXY(int index, int x, int y)
|
|
{
|
|
// Set vertices.
|
|
SetVertex(index, VTX_X, x);
|
|
SetVertex(index, VTX_Y, y);
|
|
return;
|
|
}
|
|
|
|
// Returns the number of stuck vertices. (of this)
|
|
global func VerticesStuck()
|
|
{
|
|
var vertices = 0;
|
|
// Loop through vertices.
|
|
for (var i = -1; i < GetVertexNum(); i++)
|
|
// Solid?
|
|
if (GBackSolid(GetVertex(i, VTX_X), GetVertex(i, VTX_Y)))
|
|
// Count vertices.
|
|
vertices++;
|
|
return vertices;
|
|
}
|
|
|
|
// Creates amount objects of type id inside the indicated rectangle(optional) in the indicated material.
|
|
// Returns the number of iterations needed, or -1 when the placement failed.
|
|
global func PlaceObjects(id id, int amount, string mat_str, int x, int y, int wdt, int hgt, bool onsf, bool nostuck)
|
|
{
|
|
var i, j;
|
|
var rndx, rndy, obj;
|
|
var mtype, mat;
|
|
var func, objhgt = id->GetDefCoreVal("Height", "DefCore");
|
|
|
|
mat = Material(mat_str);
|
|
// Some failsavety.
|
|
if (mat == -1)
|
|
if (mat_str != "GBackSolid" && mat_str != "GBackSemiSolid" && mat_str != "GBackLiquid" && mat_str != "GBackSky")
|
|
return -1;
|
|
|
|
// Optional parameters wdt and hgt.
|
|
if (!wdt)
|
|
wdt = LandscapeWidth() - x - GetX();
|
|
if (!hgt)
|
|
hgt = LandscapeHeight() - y - GetY();
|
|
|
|
// Cycle-saving method.
|
|
if (mat != -1)
|
|
while (i < amount)
|
|
{
|
|
// If there's isn't any or not enough of the given material, break before it gets an endless loop.
|
|
if (j++ > 20000)
|
|
return -1;
|
|
// Destinated rectangle.
|
|
rndx = x + Random(wdt);
|
|
rndy = y + Random(hgt);
|
|
// Positioning.
|
|
if (GetMaterial(rndx, rndy) == mat)
|
|
{
|
|
// On-surface option.
|
|
if (onsf)
|
|
while (GBackSemiSolid(rndx, rndy) && rndy >= y)
|
|
rndy--;
|
|
if (rndy < y)
|
|
continue;
|
|
// Create and verify stuckness.
|
|
obj = CreateObject(id, rndx, rndy + objhgt / 2, NO_OWNER);
|
|
obj->SetR(Random(360));
|
|
if (obj->Stuck() || nostuck)
|
|
i++;
|
|
else
|
|
obj->RemoveObject();
|
|
}
|
|
}
|
|
|
|
if (mat == -1)
|
|
while (i < amount)
|
|
{
|
|
// If there's isn't any or not enough of the given material, break before it gets an endless loop.
|
|
if (j++ > 20000)
|
|
return -1;
|
|
// Destinated rectangle.
|
|
rndx = x + Random(wdt);
|
|
rndy = y + Random(hgt);
|
|
// Positioning.
|
|
if (eval(Format("%s(%d,%d)", mat_str, rndx, rndy)))
|
|
{
|
|
// On-surface Option.
|
|
if (onsf)
|
|
while (GBackSemiSolid(rndx, rndy) && rndy >= y)
|
|
rndy--;
|
|
if (rndy < y)
|
|
continue;
|
|
// Create and verify stuckness.
|
|
obj = CreateObject(id, rndx, rndy + objhgt / 2, NO_OWNER);
|
|
obj->SetR(Random(360));
|
|
if (obj->Stuck() || nostuck)
|
|
i++;
|
|
else
|
|
obj->RemoveObject();
|
|
}
|
|
}
|
|
|
|
return j;
|
|
}
|
|
|
|
global func CastObjects(id def, int am, int lev, int x, int y, int angs, int angw)
|
|
{
|
|
if (!angw)
|
|
angw = 360;
|
|
for (var i = 0; i < am; i++)
|
|
{
|
|
var obj = CreateObject(def , x, y, NO_OWNER);
|
|
var ang = angs - 90 + RandomX(-angw / 2, angw / 2);
|
|
var xdir = Cos(ang, lev) + RandomX(-3, 3);
|
|
obj->SetR(Random(360));
|
|
obj->SetXDir(xdir);
|
|
obj->SetYDir(Sin(ang, lev) + RandomX(-3, 3));
|
|
if(xdir != 0) obj->SetRDir((10 + Random(21)) * (xdir / Abs(xdir)));
|
|
else
|
|
obj->SetRDir(-10 + Random(21));
|
|
}
|
|
return;
|
|
}
|
|
|
|
global func CastPXS(string mat, int am, int lev, int x, int y, int angs, int angw)
|
|
{
|
|
if (!angw)
|
|
angw = 360;
|
|
for (var i = 0; i < am; i++)
|
|
{
|
|
var ang = angs - 90 + RandomX(-angw / 2, angw / 2);
|
|
InsertMaterial(Material(mat), x, y, Cos(ang, lev) + RandomX(-3, 3), Sin(ang, lev) + RandomX(-3, 3));
|
|
}
|
|
return;
|
|
}
|
|
|
|
global func CheckVisibility(int plr)
|
|
{
|
|
var visible = this["Visibility"];
|
|
if (GetType(visible) == C4V_Array)
|
|
visible = visible[0];
|
|
|
|
// Not visible at all.
|
|
if (visible == VIS_None)
|
|
return false;
|
|
// Visible for all.
|
|
if (visible == VIS_All)
|
|
return true;
|
|
|
|
// Object is owned by the indicated player.
|
|
if (GetOwner() == plr)
|
|
{
|
|
if (visible & VIS_Owner)
|
|
return true;
|
|
}
|
|
// Object belongs to a player, hostile to plr.
|
|
else if (Hostile(GetOwner(), plr))
|
|
{
|
|
if (visible & VIS_Enemies)
|
|
return true;
|
|
}
|
|
// Object belongs to a player, friendly to plr.
|
|
else
|
|
{
|
|
if (visible & VIS_Allies)
|
|
return true;
|
|
}
|
|
|
|
if (visible & VIS_Select)
|
|
if (this["Visibility"][1 + plr / 32] & 1 << plr)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
global func MaterialDepthCheck(int x, int y, string mat, int depth)
|
|
{
|
|
var travelled;
|
|
var xval = x;
|
|
var yval = y;
|
|
|
|
//If depth is equal to zero, the function will always measure the depth of the material.
|
|
//If depth is not equal to zero, the function will return true if the material is as deep or deeper than depth (in pixels).
|
|
if (depth == nil)
|
|
depth = LandscapeHeight();
|
|
|
|
while (travelled != depth)
|
|
{
|
|
if (GetMaterial(xval, yval) == Material(mat))
|
|
{
|
|
travelled++;
|
|
yval++;
|
|
}
|
|
if (GetMaterial(xval, yval) != Material(mat))
|
|
return travelled; // Returns depth of material.
|
|
}
|
|
if (travelled == depth)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
global func LaunchProjectile(int angle, int dist, int speed, int x, int y, bool rel_x)
|
|
{
|
|
// dist: Distance object travels on angle. Offset from calling object.
|
|
// x: X offset from container's center
|
|
// y: Y offset from container's center
|
|
// rel_x: if true, makes the X offset relative to container direction. (x=+30 will become x=-30 when Clonk turns left. This way offset always stays in front of a Clonk.)
|
|
|
|
var x_offset = Sin(angle, dist);
|
|
var y_offset = -Cos(angle, dist);
|
|
|
|
if (Contained() != nil && rel_x == true)
|
|
if (Contained()->GetDir() == 0)
|
|
x = -x;
|
|
|
|
if (Contained() != nil)
|
|
{
|
|
Exit(x_offset + x, y_offset + y, angle);
|
|
SetVelocity(angle, speed);
|
|
return true;
|
|
}
|
|
|
|
if (Contained() == nil)
|
|
{
|
|
SetPosition(GetX() + x_offset + x, GetY() + y_offset + y);
|
|
SetR(angle);
|
|
SetVelocity(angle, speed);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
global func ComDirLike(int comdir1, int comdir2)
|
|
{
|
|
if (comdir1 == comdir2)
|
|
return true;
|
|
if (comdir1 == COMD_Stop || comdir2 == COMD_Stop)
|
|
return false;
|
|
if (comdir1 == COMD_None || comdir2 == COMD_None)
|
|
return false;
|
|
if (comdir1 % 8 + 1 == comdir2)
|
|
return true;
|
|
if (comdir1 == comdir2 % 8 + 1)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
global func SetObjAlpha(int by_alpha)
|
|
{
|
|
var clr_mod = GetClrModulation();
|
|
|
|
if (!clr_mod)
|
|
clr_mod = by_alpha << 24;
|
|
else
|
|
clr_mod = clr_mod & 16777215 | by_alpha << 24;
|
|
return SetClrModulation(clr_mod);
|
|
}
|
|
|
|
global func FindPosInMat(string sMat, int iXStart, int iYStart, int iWidth, int iHeight, int iSize)
|
|
{
|
|
var iX, iY;
|
|
var iMaterial = Material(sMat);
|
|
for(var i = 0; i < 500; i++)
|
|
{
|
|
iX = AbsX(iXStart+Random(iWidth));
|
|
iY = AbsY(iYStart+Random(iHeight));
|
|
if(GetMaterial(iX,iY)==iMaterial &&
|
|
GetMaterial(iX+iSize,iY+iSize)==iMaterial &&
|
|
GetMaterial(iX+iSize,iY-iSize)==iMaterial &&
|
|
GetMaterial(iX-iSize,iY-iSize)==iMaterial &&
|
|
GetMaterial(iX-iSize,iY+iSize)==iMaterial
|
|
) {
|
|
return [iX, iY]; // Location found.
|
|
}
|
|
}
|
|
return 0; // No location found.
|
|
}
|