New: Cotton, Cotton Seed, Cloth, Seed Library
After Width: | Height: | Size: 5.0 KiB |
|
@ -0,0 +1,3 @@
|
|||
[Particle]
|
||||
Name=CottonBalloon
|
||||
Face=0,0,32,32,-16,-16
|
|
@ -2,14 +2,14 @@
|
|||
id=Cloth
|
||||
Version=6,0
|
||||
Category=C4D_Object
|
||||
Width=8
|
||||
Height=4
|
||||
Offset=-4,-2
|
||||
Vertices=3
|
||||
VertexX=0,3,-3
|
||||
VertexY=0,1,1
|
||||
VertexFriction=50,100,100
|
||||
Width=12
|
||||
Height=12
|
||||
Offset=-6,-6
|
||||
Vertices=4
|
||||
VertexX=-4,-4,4,4
|
||||
VertexY=4,-4,4,-4
|
||||
VertexFriction=100,100,100,100
|
||||
Value=10
|
||||
Mass=1
|
||||
Components=Cotton=1
|
||||
Picture=32,0,64,64
|
||||
Components=CottonSeed=1
|
||||
Rotate=1
|
Before Width: | Height: | Size: 5.7 KiB |
|
@ -0,0 +1,21 @@
|
|||
material Fabric_carryheavy
|
||||
{
|
||||
receive_shadows on
|
||||
technique
|
||||
{
|
||||
pass
|
||||
{
|
||||
ambient 0.800000011920929 0.800000011920929 0.800000011920929 1.0
|
||||
diffuse 0.800000011920929 0.800000011920929 0.800000011920929 1.0
|
||||
specular 0.0 0.0 0.0 1.0 12.5
|
||||
emissive 0.0 0.0 0.0 1.0
|
||||
|
||||
texture_unit
|
||||
{
|
||||
texture fabric.png
|
||||
tex_address_mode wrap
|
||||
filtering trilinear
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +1,27 @@
|
|||
/*-- Cloth --*/
|
||||
|
||||
protected func Hit()
|
||||
#include Library_CarryHeavy
|
||||
|
||||
public func GetCarryMode(clonk) { return CARRY_BothHands; }
|
||||
public func GetCarryPhase() { return 800; }
|
||||
public func GetCarryTransform(clonk)
|
||||
{
|
||||
if(GetCarrySpecial(clonk))
|
||||
return Trans_Translate(2000, 4500, 6500);
|
||||
}
|
||||
|
||||
private func Hit()
|
||||
{
|
||||
Sound("GeneralHit?");
|
||||
}
|
||||
|
||||
public func IsLoomProduct() { return true; }
|
||||
|
||||
private func Definition(def)
|
||||
{
|
||||
SetProperty("PictureTransformation", Trans_Mul(Trans_Rotate(-45,1), Trans_Rotate(-20,0,0,1)), def);
|
||||
}
|
||||
|
||||
local Name = "$Name$";
|
||||
local Description = "$Description$";
|
||||
local Collectible = 1;
|
||||
|
|
After Width: | Height: | Size: 74 KiB |
After Width: | Height: | Size: 4.0 MiB |
|
@ -1,13 +0,0 @@
|
|||
[DefCore]
|
||||
id=Cotton
|
||||
Version=6,0
|
||||
Category=C4D_Object
|
||||
Width=8
|
||||
Height=8
|
||||
Offset=-4,-4
|
||||
Vertices=2
|
||||
VertexX=0,0
|
||||
VertexY=1,-1
|
||||
VertexFriction=40,40,40
|
||||
Value=5
|
||||
Mass=1
|
Before Width: | Height: | Size: 6.8 KiB |
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
Cotton
|
||||
Author: Clonkonaut
|
||||
|
||||
For planting cotton plants or to get cloth
|
||||
*/
|
||||
|
||||
/*public func ControlUse(object clonk, int x, int y, bool box)
|
||||
{
|
||||
if(clonk->GetAction() != "Walk") return true;
|
||||
// Search for ground
|
||||
x = 0; y = 0;
|
||||
if (GBackSemiSolid(x,y)) return true;
|
||||
var i = 0;
|
||||
while (!GBackSolid(x,y) && i < 15) { ++y; ++i; }
|
||||
if (!GBackSolid(x,y)) return true;
|
||||
if (GetMaterialVal("Soil", "Material", GetMaterial(x,y)) == 1)
|
||||
{
|
||||
// Plant!
|
||||
clonk->DoKneel();
|
||||
CreateObjectAbove(Wheat, x, y, clonk->GetOwner())->SetCon(1);
|
||||
RemoveObject();
|
||||
}
|
||||
else
|
||||
clonk->Message("$NoSuitableGround$");
|
||||
|
||||
return true;
|
||||
}*/
|
||||
|
||||
protected func Hit()
|
||||
{
|
||||
Sound("GeneralHit?");
|
||||
}
|
||||
|
||||
public func IsLoomIngredient() { return true; }
|
||||
|
||||
local Collectible = 1;
|
||||
local Name = "$Name$";
|
||||
local Description = "$Description$";
|
||||
local UsageHelp = "$UsageHelp$";
|
||||
local Rebuy = true;
|
||||
local Plane = 460;
|
|
@ -1,4 +0,0 @@
|
|||
Name=Baumwolle
|
||||
Description=Baumwolle zum Anpflanzen oder Verarbeiten zu Stoff
|
||||
UsageHelp=Drücke [Benutzen] um hier eine Baumwollpflanze anzupflanzen.
|
||||
NoSuitableGround=Untergrund ist zum|Anbau nicht geeignet!
|
|
@ -1,4 +0,0 @@
|
|||
Name=Cotton
|
||||
Description=Cotton for planting a cotton plant or producing cloth.
|
||||
UsageHelp=Press [Use] to plant a cotton plant here.
|
||||
NoSuitableGround=Ground not suitable|for planting!
|
|
@ -0,0 +1,13 @@
|
|||
[DefCore]
|
||||
id=CottonSeed
|
||||
Version=6,1
|
||||
Category=C4D_Object
|
||||
Width=11
|
||||
Height=11
|
||||
Offset=-5,-5
|
||||
Vertices=3
|
||||
VertexX=0,3,-3
|
||||
VertexY=4,-4,-4
|
||||
VertexFriction=40,40,40
|
||||
Value=5
|
||||
Mass=1
|
|
@ -0,0 +1,24 @@
|
|||
material cotton_seed
|
||||
{
|
||||
receive_shadows on
|
||||
technique
|
||||
{
|
||||
pass
|
||||
{
|
||||
cull_hardware none
|
||||
depth_check on
|
||||
|
||||
ambient 1.0 1.0 1.0 1.0
|
||||
diffuse 1.0 1.0 1.0 1.0
|
||||
specular 0.0 0.0 0.0 1.0 12.5
|
||||
emissive 0.0 0.0 0.0 1.0
|
||||
|
||||
texture_unit
|
||||
{
|
||||
texture cotton_seed.png
|
||||
tex_address_mode wrap
|
||||
filtering trilinear
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
Cotton Seed
|
||||
Author: Clonkonaut
|
||||
|
||||
For planting cotton plants or to get cloth
|
||||
*/
|
||||
|
||||
#include Library_Seed
|
||||
|
||||
local lib_seed_plant = Cotton;
|
||||
|
||||
public func GetCarryMode() { return CARRY_HandBack; }
|
||||
public func GetCarryBone() { return "main"; }
|
||||
|
||||
private func Hit()
|
||||
{
|
||||
Sound("GeneralHit?");
|
||||
}
|
||||
|
||||
local Collectible = 1;
|
||||
local Name = "$Name$";
|
||||
local Description = "$Description$";
|
||||
local Rebuy = true;
|
||||
local Plane = 460;
|
||||
local BlastIncinerate = 5;
|
||||
local ContactIncinerate = 2;
|
|
@ -0,0 +1,4 @@
|
|||
Name=Baumwollsamen
|
||||
Description=Baumwollsamen können angepflanzt oder zu Stoff verarbeitet werden.
|
||||
UsageHelp=Drücke [Benutzen] um hier eine Baumwollpflanze anzupflanzen.
|
||||
NoSuitableGround=Untergrund ist zum|Anbau nicht geeignet!
|
|
@ -0,0 +1,4 @@
|
|||
Name=Cotton Seed
|
||||
Description=Cotton seed may be sown or fabricated into cloth.
|
||||
UsageHelp=Press [Use] to plant a cotton plant here.
|
||||
NoSuitableGround=Ground not suitable|for planting!
|
After Width: | Height: | Size: 139 KiB |
|
@ -0,0 +1,4 @@
|
|||
[DefCore]
|
||||
id=Library_Seed
|
||||
Version=6,1
|
||||
Category=C4D_StaticBack
|
|
@ -0,0 +1,151 @@
|
|||
/**
|
||||
Seed
|
||||
|
||||
Logic for plant seed that will eventually sprout a plant if left alone long enough.
|
||||
Seeds may also be manually planted by using leftclick.
|
||||
|
||||
@author Clonkonaut
|
||||
*/
|
||||
|
||||
// The last known position of the seed
|
||||
local lib_seed_pos;
|
||||
// The timer cycles the seed has been lying idly (until it has reached 10)
|
||||
local lib_seed_idletime = 0;
|
||||
// The time it takes until a new plant might be created, feel free to reassign
|
||||
local lib_seed_planttime = 10500;
|
||||
|
||||
// ****** Must be the id of the plant to create. Do not leave empty.
|
||||
local lib_seed_plant;
|
||||
|
||||
/* Reproduction control */
|
||||
|
||||
/** Distance the seeds checks for plants. Default is 250.
|
||||
@return the maximum distance.
|
||||
*/
|
||||
private func SeedArea()
|
||||
{
|
||||
return 250;
|
||||
}
|
||||
/** The amount of plants allowed within SeedArea. Default is 10.
|
||||
@return the maximum amount of plants.
|
||||
*/
|
||||
private func SeedAmount()
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
/** The closest distance a new plant may seed to its nearest neighbour. Default is 20.
|
||||
@return the maximum amount of plants.
|
||||
*/
|
||||
private func SeedOffset()
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
|
||||
/* Reproduction */
|
||||
|
||||
private func Initialize()
|
||||
{
|
||||
AddTimer("CheckSprout", lib_seed_planttime / 10);
|
||||
lib_seed_pos = { x = GetX(), y = GetY() };
|
||||
}
|
||||
|
||||
// Check whether a plant should be created
|
||||
private func CheckSprout()
|
||||
{
|
||||
if (Contained()) return;
|
||||
if (OnFire()) return;
|
||||
if (!CheckPosition()) return;
|
||||
|
||||
lib_seed_idletime++;
|
||||
if (lib_seed_idletime >= 10)
|
||||
{
|
||||
// Is this place nice to make a new plant?
|
||||
if (!CheckPlantConditions())
|
||||
lib_seed_idletime = 0;
|
||||
else
|
||||
Sprout();
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether the seed was moved
|
||||
private func CheckPosition()
|
||||
{
|
||||
if (GetX() != lib_seed_pos.x || GetY() != lib_seed_pos.y)
|
||||
{
|
||||
lib_seed_pos.x = GetX();
|
||||
lib_seed_pos.y = GetY();
|
||||
lib_seed_idletime = 0;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Sprouting */
|
||||
|
||||
// Returns the relative y to the ground from center to max 20 pixels.
|
||||
// If no ground is found returns -1, also if the center is underground (stuck in material)
|
||||
private func GetGroundPos()
|
||||
{
|
||||
if (GBackSolid()) return -1;
|
||||
|
||||
var y = 0;
|
||||
while (!GBackSolid(0,y) && y < 21)
|
||||
y++;
|
||||
if (y >= 21) return -1;
|
||||
return y;
|
||||
}
|
||||
|
||||
/** Overload as necessary to check for further conditions. Return true if a new plant should be created.
|
||||
*/
|
||||
private func CheckPlantConditions()
|
||||
{
|
||||
var ground = GetGroundPos();
|
||||
// No solid ground
|
||||
if (ground == -1) return false;
|
||||
// No fertile ground
|
||||
if (GetMaterialVal("Soil", "Material", GetMaterial(0,ground)) != 1) return false;
|
||||
// Do not grow underground
|
||||
if (!GBackSky(0, ground-1) && !GBackSky(0,0) && !GBackSky(0,-30)) return false;
|
||||
// Too many plants around
|
||||
var size = SeedArea();
|
||||
if (ObjectCount(Find_ID(lib_seed_plant), Find_InRect(-size / 2, -size / 2, size, size)) > SeedAmount()) return false;
|
||||
// Another plant too close
|
||||
var neighbour = FindObject(Find_ID(lib_seed_plant), Sort_Distance());
|
||||
if (neighbour)
|
||||
if (ObjectDistance(neighbour) < SeedOffset())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Overload as necessary. Should remove the seed.
|
||||
*/
|
||||
private func Sprout()
|
||||
{
|
||||
var ground = GetGroundPos();
|
||||
var plant = CreateObjectAbove(lib_seed_plant, 0, ground, GetOwner());
|
||||
if (!plant) return; // What now?
|
||||
plant->SetCon(1);
|
||||
RemoveObject();
|
||||
}
|
||||
|
||||
/* Planting */
|
||||
|
||||
public func ControlUse(object clonk, int x, int y, bool box)
|
||||
{
|
||||
if(!clonk->~IsWalking()) return true;
|
||||
var ground = GetGroundPos();
|
||||
if (ground == -1)
|
||||
return CustomMessage(Format("$TxtBadGround$", GetName()), clonk, clonk->GetController(), 0, 0, 0xff0000);
|
||||
|
||||
// Soil is needed
|
||||
if (GetMaterialVal("Soil", "Material", GetMaterial(0,ground)) != 1)
|
||||
return CustomMessage(Format("$TxtBadGround$", GetName()), clonk, clonk->GetController(), 0, 0, 0xff0000);
|
||||
|
||||
// Plant!
|
||||
clonk->DoKneel();
|
||||
Sprout();
|
||||
return true;
|
||||
}
|
||||
|
||||
local UsageHelp = "$UsageHelp$";
|
|
@ -0,0 +1,2 @@
|
|||
TxtBadGround=%s kann hier|nicht gepflanzt werden!
|
||||
UsageHelp=Drücke [Benutzen] zum Anpflanzen.
|
|
@ -0,0 +1,2 @@
|
|||
TxtBadGround=Can't plant %s here!
|
||||
UsageHelp=Press [Use] to plant.
|
|
@ -0,0 +1,7 @@
|
|||
[DefCore]
|
||||
id=Cotton_Branch
|
||||
Version=6,1
|
||||
Category=C4D_StaticBack
|
||||
Width=20
|
||||
Height=16
|
||||
Offset=-10,-8
|
|
@ -0,0 +1,24 @@
|
|||
material Cotton_Branch
|
||||
{
|
||||
receive_shadows on
|
||||
technique
|
||||
{
|
||||
pass
|
||||
{
|
||||
cull_hardware clockwise
|
||||
depth_check on
|
||||
|
||||
ambient 1.0 1.0 1.0 1.0
|
||||
diffuse 1.0 1.0 1.0 1.0
|
||||
specular 0.0 0.0 0.0 1.0 12.5
|
||||
emissive 0.0 0.0 0.0 1.0
|
||||
|
||||
texture_unit
|
||||
{
|
||||
texture cottonbranch.png
|
||||
tex_address_mode wrap
|
||||
filtering trilinear
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 623 KiB |
|
@ -0,0 +1,11 @@
|
|||
[DefCore]
|
||||
id=Cotton_Fruit
|
||||
Version=6,1
|
||||
Width=11
|
||||
Height=11
|
||||
Offset=-5,-5
|
||||
Vertices=3
|
||||
VertexX=0,3,-3
|
||||
VertexY=4,-4,-4
|
||||
VertexFriction=10,10,10
|
||||
BorderBound=1
|
|
@ -0,0 +1,42 @@
|
|||
material Cotton_Fruit
|
||||
{
|
||||
receive_shadows on
|
||||
technique
|
||||
{
|
||||
pass
|
||||
{
|
||||
cull_hardware none
|
||||
scene_blend alpha_blend
|
||||
depth_check on
|
||||
alpha_rejection greater_equal 128
|
||||
|
||||
ambient 1.0 1.0 1.0 1.0
|
||||
diffuse 1.0 1.0 1.0 1.0
|
||||
specular 0.0 0.0 0.0 1.0 12.5
|
||||
emissive 0.0 0.0 0.0 1.0
|
||||
|
||||
texture_unit
|
||||
{
|
||||
texture cottonfruit_growing.png
|
||||
tex_address_mode wrap
|
||||
filtering trilinear
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
material Cotton_Fruit_Ripe: Cotton_Fruit
|
||||
{
|
||||
technique 0
|
||||
{
|
||||
pass 0
|
||||
{
|
||||
texture_unit
|
||||
{
|
||||
texture cottonfruit.png
|
||||
tex_address_mode wrap
|
||||
filtering trilinear
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,214 @@
|
|||
/*
|
||||
Cotton Fruit
|
||||
Author: Clonkonaut, Win
|
||||
*/
|
||||
|
||||
// Animation length is 875
|
||||
// At about 500 the fruit starts filling up with gas
|
||||
local first_animation_stage = 500;
|
||||
// Growing time for first stage in frames
|
||||
local grow_time = 3100;
|
||||
local grow_anim;
|
||||
local attach_branch;
|
||||
// Filling time & also animation duration for second stage
|
||||
local fill_time = 3100;
|
||||
// When the balloon is full of gas, it's ripe!
|
||||
local ripened = false;
|
||||
// Time the filled balloon will stay on the branch (time the player has to prepare for harvesting)
|
||||
local ripe_time = 3500;
|
||||
// Time the player has for harvesting before the balloon starts rising
|
||||
local float_time = 350;
|
||||
// Half of the time the balloon will fly up and half will just drift with the wind
|
||||
local fly_time = 700;
|
||||
|
||||
private func Construction()
|
||||
{
|
||||
SetProperty("MeshTransformation", Trans_Rotate(180, 0,0,1));
|
||||
}
|
||||
|
||||
/* Growing & filling with gas */
|
||||
|
||||
public func Grow(int branch, bool fullgrown)
|
||||
{
|
||||
attach_branch = branch;
|
||||
if (!fullgrown)
|
||||
{
|
||||
grow_anim = PlayAnimation("grow", 1, Anim_Linear(0,0, first_animation_stage, grow_time, ANIM_Hold), Anim_Const(1000));
|
||||
AddTimer("Growing", 35);
|
||||
ScheduleCall(this, "Fill", grow_time);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!grow_anim) grow_anim = PlayAnimation("grow", 1, Anim_Linear(GetAnimationLength("grow"),0, GetAnimationLength("grow"), 1, ANIM_Hold), Anim_Const(1000));
|
||||
else SetAnimationPosition(grow_anim, Anim_Const(GetAnimationLength("grow")));
|
||||
if (Contained())
|
||||
{
|
||||
Contained()->UpdateFruitAttachTransform(attach_branch, 2000);
|
||||
Contained()->FruitFills(attach_branch, nil, true);
|
||||
}
|
||||
Ripen();
|
||||
}
|
||||
}
|
||||
|
||||
public func IsGrowing()
|
||||
{
|
||||
return !ripened;
|
||||
}
|
||||
|
||||
// Every ~1 second update scaling on cotton plant
|
||||
private func Growing()
|
||||
{
|
||||
// Shouldn't happen
|
||||
if (!Contained()) return RemoveTimer("Growing");
|
||||
Contained()->UpdateFruitAttachTransform(attach_branch, GetAnimationPosition(grow_anim) * 1000 / first_animation_stage);
|
||||
if (GetAnimationPosition(grow_anim) >= first_animation_stage) RemoveTimer("Growing");
|
||||
}
|
||||
|
||||
// The fruit is now grown and starts filling with gas, this will also move the branch
|
||||
private func Fill()
|
||||
{
|
||||
// No plant, no fill
|
||||
if (!Contained()) return;
|
||||
SetAnimationPosition(grow_anim, Anim_Linear(GetAnimationPosition(grow_anim), 0, GetAnimationLength("grow"), fill_time, ANIM_Hold));
|
||||
Contained()->FruitFills(attach_branch, fill_time, false); // Will start the branch's animation
|
||||
ScheduleCall(this, "Ripen", fill_time);
|
||||
}
|
||||
|
||||
/* Ripening & Flying */
|
||||
|
||||
private func Ripen()
|
||||
{
|
||||
SetMeshMaterial("Cotton_Fruit_Ripe");
|
||||
ripened = true;
|
||||
AddEffect("IntPrepareFlight", this, 1, 1, this);
|
||||
}
|
||||
|
||||
private func FxIntPrepareFlightTimer(object target, proplist effect, int time)
|
||||
{
|
||||
if (!Contained()) return FX_Execute_Kill;
|
||||
if (time > 10 && !effect.shakes)
|
||||
{
|
||||
effect.shakes = 1;
|
||||
Contained()->ShakeFruit(attach_branch);
|
||||
}
|
||||
if (time > ripe_time / 2 && effect.shakes == 1)
|
||||
{
|
||||
effect.shakes = 2;
|
||||
Contained()->ShakeFruit(attach_branch);
|
||||
}
|
||||
if (time >= ripe_time)
|
||||
{
|
||||
Fly();
|
||||
return FX_Execute_Kill;
|
||||
}
|
||||
return FX_OK;
|
||||
}
|
||||
|
||||
// May be called from elsewhere e.g. the cotton plant when harvesting with a sickle
|
||||
public func Fly() // you fools
|
||||
{
|
||||
var plant = Contained();
|
||||
if (plant)
|
||||
{
|
||||
var pos = plant->GetFruitExitPosition(attach_branch);
|
||||
Exit(pos.x, pos.y);
|
||||
plant->DetachFruit(attach_branch); // bye-bye
|
||||
}
|
||||
SetAction("Fly");
|
||||
SetYDir(-1);
|
||||
var effect = AddEffect("IntFlight", this, 1, 5, this);
|
||||
effect.random = Random(360);
|
||||
}
|
||||
|
||||
private func FxIntFlightTimer(object target, proplist effect, int time)
|
||||
{
|
||||
var xdir = GetXDir();
|
||||
var ydir = GetYDir();
|
||||
if (time < float_time)
|
||||
{
|
||||
ydir += Sin(time + effect.random, 2);
|
||||
}
|
||||
// Fly upwards
|
||||
if (time > float_time)
|
||||
{
|
||||
if (time < float_time + fly_time / 2)
|
||||
ydir -= Max(Tan((900 - time + float_time)%900, 10, 10), 0);
|
||||
// Fly with the wind
|
||||
if (GetWind())
|
||||
xdir += Tan((time - float_time)%900, GetWind(), 10);
|
||||
else if (xdir != 0)
|
||||
xdir -= xdir / Abs(xdir);
|
||||
}
|
||||
if (time > float_time + fly_time / 2)
|
||||
{
|
||||
if (ydir < 0) ydir += 1;
|
||||
// ~1 second until pop!
|
||||
}
|
||||
if (time > float_time + fly_time + 35)
|
||||
{
|
||||
Pop();
|
||||
// Pop deletes this object
|
||||
return FX_Execute_Kill;
|
||||
}
|
||||
|
||||
SetSpeed(xdir, ydir);
|
||||
SetProperty("MeshTransformation", Trans_Rotate(180 + BoundBy(xdir, -50, 50), 0,0,1));
|
||||
return FX_OK;
|
||||
}
|
||||
|
||||
/* Shooting, harvesting, popping */
|
||||
|
||||
public func IsProjectileTarget() { return true; }
|
||||
public func IsHarvestable() { return true; }
|
||||
public func SickleHarvesting() { return true; }
|
||||
|
||||
public func OnProjectileHit() { Pop(); }
|
||||
public func Damage() { Pop(); }
|
||||
public func Harvest() { Pop(); }
|
||||
|
||||
public func Pop()
|
||||
{
|
||||
CreateParticle("CottonBalloon", 0,0, PV_Random(-15,15), PV_Random(-10,-5), 100, Particles_CottonBalloon(), RandomX(4,8));
|
||||
var seed = CreateObject(CottonSeed);
|
||||
if (OnFire()) seed->Incinerate();
|
||||
RemoveObject();
|
||||
}
|
||||
|
||||
/*-- Saving --*/
|
||||
|
||||
public func SaveScenarioObject(proplist props)
|
||||
{
|
||||
// Do not save fruit inside a cotton plant
|
||||
if (Contained())
|
||||
if (Contained()->GetID() == Cotton)
|
||||
return false;
|
||||
var effect;
|
||||
if (effect = GetEffect("IntFlight", this))
|
||||
{
|
||||
props->AddCall("Flight", this, "ResumeFlight", effect.time, effect.random);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Loading
|
||||
private func ResumeFlight(int effect_time, int effect_random)
|
||||
{
|
||||
var effect = AddEffect("IntFlight", this, 1, 5, this);
|
||||
effect.time = effect_time;
|
||||
effect.random = effect_random;
|
||||
}
|
||||
|
||||
local ActMap = {
|
||||
Fly = {
|
||||
Prototype = Action,
|
||||
Name = "Fly",
|
||||
Procedure = DFA_FLOAT,
|
||||
Speed = 50,
|
||||
Accel = 5,
|
||||
NextAction = "Fly",
|
||||
},
|
||||
};
|
||||
|
||||
local Plane = 460;
|
||||
local BlastIncinerate = 1;
|
||||
local ContactIncinerate = 3;
|
|
@ -0,0 +1,2 @@
|
|||
Name=Baumwollfrucht
|
||||
Description=Ein gasgefüllter Ballon, der die begehrte Wolle birgt. Beim Treffer von einer Waffe platzt der Ballon.
|
|
@ -0,0 +1,2 @@
|
|||
Name=Cotton fruit
|
||||
Description=A gas filled balloon that holds the precious cotton. Strike with any weapon to let it pop.
|
After Width: | Height: | Size: 501 KiB |
After Width: | Height: | Size: 285 KiB |
|
@ -0,0 +1,15 @@
|
|||
[DefCore]
|
||||
id=Cotton
|
||||
Version=6,1
|
||||
Category=C4D_StaticBack
|
||||
Width=20
|
||||
Height=36
|
||||
Offset=-10,-18
|
||||
Vertices=2
|
||||
VertexX=0,0
|
||||
VertexY=17,19
|
||||
VertexCNAT=16,8
|
||||
VertexFriction=10,100
|
||||
Mass=6
|
||||
StretchGrowth=4
|
||||
Oversize=1
|
|
@ -0,0 +1,25 @@
|
|||
material Cotton_Bush
|
||||
{
|
||||
receive_shadows on
|
||||
technique
|
||||
{
|
||||
pass
|
||||
{
|
||||
cull_hardware none
|
||||
scene_blend alpha_blend
|
||||
depth_check off
|
||||
|
||||
ambient 1.0 1.0 1.0 1.0
|
||||
diffuse 1.0 1.0 1.0 1.0
|
||||
specular 0.0 0.0 0.0 1.0 12.5
|
||||
emissive 0.0 0.0 0.0 1.0
|
||||
|
||||
texture_unit
|
||||
{
|
||||
texture cotton.png
|
||||
tex_address_mode wrap
|
||||
filtering trilinear
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,354 @@
|
|||
/*
|
||||
Cotton
|
||||
Author: Clonkonaut
|
||||
|
||||
Medium crop for farming.
|
||||
*/
|
||||
|
||||
#include Library_Plant
|
||||
#include Library_Crop
|
||||
|
||||
local direction = 1;
|
||||
local capacity; // How much fruit this plant will yield
|
||||
local branches; // Array with 3 proplists containing all the needed values for the 3 branches
|
||||
local branch_proto = {
|
||||
// As returned by AttachMesh
|
||||
attach_slot = 0,
|
||||
// Growing time until ready to bear fruit, growing time afterwards is determined by the fruit
|
||||
grow_time = 4500,
|
||||
// The branch's animation length is 875, 490 marks the point just before the branch start raising up
|
||||
first_animation_stage = 490,
|
||||
// Whether the branch is ready to bear fruit yet
|
||||
grown = false,
|
||||
// As returned by PlayAnimation
|
||||
grow_animation = -1,
|
||||
// As returned by AddEffect
|
||||
grow_effect = nil,
|
||||
// The fruit object (in Contents)
|
||||
fruit = nil,
|
||||
// As returned by AttachMesh
|
||||
fruit_slot = 0,
|
||||
// Internal value to (securely) stop new fruit from growing at this branch
|
||||
no_fruit = false,
|
||||
};
|
||||
|
||||
private func Construction()
|
||||
{
|
||||
_inherited(...);
|
||||
RemoveTimer("Seed");
|
||||
capacity = Random(3) + 3;
|
||||
|
||||
StartGrowth(this.growth);
|
||||
AddTimer("WaterCheck", 70+Random(10));
|
||||
|
||||
// The mesh doesn't have more than 3 bones, beware
|
||||
branches = CreateArray(3);
|
||||
branches[0] = new branch_proto {};
|
||||
branches[1] = new branch_proto {};
|
||||
branches[2] = new branch_proto {};
|
||||
|
||||
// Make half of the plants switch direction for more variety
|
||||
if (!Random(2)) direction = -1;
|
||||
SetProperty("MeshTransformation", Trans_Rotate(RandomX(70,110) * direction, 0,1,0));
|
||||
}
|
||||
|
||||
private func Initialize()
|
||||
{
|
||||
AddTimer("Reproduction", 72);
|
||||
}
|
||||
|
||||
/* Reproduction */
|
||||
|
||||
private func Reproduction()
|
||||
{
|
||||
if (OnFire()) return;
|
||||
if (GetCon() < 100) return RemoveTimer("Reproduction");
|
||||
if (!capacity && !HasFruit()) return Perish();
|
||||
|
||||
if (CheckSeedChance())
|
||||
{
|
||||
var can_branch = GetNextGrowableBranch();
|
||||
var can_fruit = GetNextFruitableBranch();
|
||||
if ((can_branch != -1 && Random(3)) || can_fruit == -1)
|
||||
return GrowBranch();
|
||||
if (can_fruit != -1)
|
||||
{
|
||||
GrowFruit();
|
||||
capacity--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The plant will wither away after it has grown all its fruit
|
||||
private func Perish()
|
||||
{
|
||||
RemoveTimer("Reproduction");
|
||||
StartGrowth(this.degrowth);
|
||||
SetClrModulation(RGB(185, 122, 87));
|
||||
}
|
||||
|
||||
/* Branch growth */
|
||||
|
||||
// Will grow the next branch unless all 3 are grown (returns false then, true otherwise)
|
||||
// If fullgrown is true, the branch will be fully grown but not bear a fruit!
|
||||
public func GrowBranch(bool fullgrown, int branch)
|
||||
{
|
||||
if (branch != nil)
|
||||
var next_to_grow = branch;
|
||||
else
|
||||
var next_to_grow = GetNextGrowableBranch(fullgrown);
|
||||
if (next_to_grow == -1) return false;
|
||||
|
||||
if (branches[next_to_grow].grow_animation != branch_proto.grow_animation) // Already growing, fullgrown must be true
|
||||
{
|
||||
if (!fullgrown) return false; // This can't happen
|
||||
FinishBranchGrowth(next_to_grow);
|
||||
return true;
|
||||
}
|
||||
branches[next_to_grow].attach_slot = AttachMesh(Cotton_Branch, Format("Stem%d", next_to_grow + 1), "main", GetBranchAttachTransform(next_to_grow, 1));
|
||||
branches[next_to_grow].grow_animation = PlayAnimation("grow", next_to_grow + 1, Anim_Linear(0,0, branches[next_to_grow].first_animation_stage, branches[next_to_grow].grow_time, ANIM_Hold), Anim_Const(1000), nil, branches[next_to_grow].attach_slot);
|
||||
branches[next_to_grow].grow_effect = AddEffect("IntBranchGrowth", this, 1, 35, this);
|
||||
branches[next_to_grow].grow_effect.branch = next_to_grow;
|
||||
if (fullgrown) FinishBranchGrowth(next_to_grow);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Determines the next branch to grow. If fullgrown is true, growing but unfinished branches are also returned
|
||||
private func GetNextGrowableBranch(bool fullgrown)
|
||||
{
|
||||
var ret = -1;
|
||||
var i = -1;
|
||||
while(++i < GetLength(branches))
|
||||
{
|
||||
if (branches[i].grown) continue;
|
||||
if (branches[i].grow_animation != branch_proto.grow_animation && !fullgrown) continue;
|
||||
ret = i;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private func FxIntBranchGrowthTimer(object target, proplist effect, int time)
|
||||
{
|
||||
UpdateBranchAttachTransform(effect.branch, GetAnimationPosition(branches[effect.branch].grow_animation, branches[effect.branch].attach_slot) * 500 / branches[effect.branch].first_animation_stage);
|
||||
if (GetAnimationPosition(branches[effect.branch].grow_animation, branches[effect.branch].attach_slot) >= branches[effect.branch].first_animation_stage)
|
||||
FinishBranchGrowth(effect.branch);
|
||||
}
|
||||
|
||||
private func FinishBranchGrowth(int branch)
|
||||
{
|
||||
branches[branch].grown = true;
|
||||
RemoveEffect(nil, nil, branches[branch].grow_effect);
|
||||
UpdateBranchAttachTransform(branch, 500);
|
||||
SetAnimationPosition(branches[branch].grow_animation, Anim_Const(branches[branch].first_animation_stage), branches[branch].attach_slot);
|
||||
}
|
||||
|
||||
private func UpdateBranchAttachTransform(int branch, int scale)
|
||||
{
|
||||
SetAttachTransform(branches[branch].attach_slot, GetBranchAttachTransform(branch, scale));
|
||||
}
|
||||
|
||||
private func GetBranchAttachTransform(int branch, int scale)
|
||||
{
|
||||
// These transforms have been determined by careful testing
|
||||
if (branch == 0) return Trans_Mul(Trans_Rotate(-30,0,1), Trans_Rotate(-100,0,0,1), Trans_Rotate(-90,0,1), Trans_Translate(1000), Trans_Scale(scale));
|
||||
if (branch == 1) return Trans_Mul(Trans_Rotate(30,0,1), Trans_Rotate(-100,0,0,1), Trans_Rotate(90,0,1), Trans_Translate(1000), Trans_Scale(scale));
|
||||
if (branch == 2) return Trans_Mul(Trans_Rotate(-100,0,0,1), Trans_Rotate(-90,0,1), Trans_Scale(scale));
|
||||
}
|
||||
|
||||
/* Fruit growth */
|
||||
|
||||
// Will grow a fruit but only if there's a fully grown branch without a fruit available
|
||||
// If fullgrown is true, the fruit will be ripe immediately. If there was no full grown branch, a branch will also be complete.
|
||||
// Does return the fruit object or nil
|
||||
public func GrowFruit(bool fullgrown)
|
||||
{
|
||||
var next_to_grow = GetNextFruitableBranch(fullgrown);
|
||||
if (next_to_grow == -1) return nil;
|
||||
|
||||
if (branches[next_to_grow].fruit) // Already growing, fullgrown must be true
|
||||
{
|
||||
if (!fullgrown) return false; // This can't happen
|
||||
branches[next_to_grow].fruit->Grow(next_to_grow, fullgrown);
|
||||
return branches[next_to_grow].fruit;
|
||||
}
|
||||
if (!branches[next_to_grow].grown)
|
||||
GrowBranch(fullgrown, next_to_grow);
|
||||
|
||||
branches[next_to_grow].fruit = CreateContents(Cotton_Fruit);
|
||||
if (!branches[next_to_grow].fruit) return false;
|
||||
branches[next_to_grow].fruit_slot = AttachMesh(branches[next_to_grow].fruit, "fruit_target", "leafes", GetFruitAttachTransform(1, 0), nil, branches[next_to_grow].attach_slot);
|
||||
branches[next_to_grow].fruit->Grow(next_to_grow, fullgrown);
|
||||
return branches[next_to_grow].fruit;
|
||||
}
|
||||
|
||||
// Determines the next brnach to grow a fruit. If fullgrown is true, unfinished branches are also returned
|
||||
private func GetNextFruitableBranch(bool fullgrown)
|
||||
{
|
||||
var ret = -1;
|
||||
var i = -1;
|
||||
while(++i < GetLength(branches))
|
||||
{
|
||||
if (branches[i].no_fruit) continue;
|
||||
if (branches[i].fruit && !(fullgrown && branches[i].fruit->IsGrowing())) continue;
|
||||
if (!branches[i].grown && !fullgrown) continue;
|
||||
ret = i;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Usually called by the fruit
|
||||
public func UpdateFruitAttachTransform(int branch, int scale)
|
||||
{
|
||||
SetAttachTransform(branches[branch].fruit_slot, GetFruitAttachTransform(scale, 0));
|
||||
}
|
||||
|
||||
private func GetFruitAttachTransform(int scale, int extra_r)
|
||||
{
|
||||
return Trans_Mul(Trans_Rotate(180, 0,1,0), Trans_Rotate(extra_r, 0,0,1), Trans_Scale(scale));
|
||||
}
|
||||
|
||||
// Called by the fruit when the first growing animation is done
|
||||
// The branch will restart its animation with duration of time
|
||||
public func FruitFills(int branch, int time, bool fullgrown)
|
||||
{
|
||||
var pos = GetAnimationPosition(branches[branch].grow_animation, branches[branch].attach_slot);
|
||||
if (fullgrown)
|
||||
SetAnimationPosition(branches[branch].grow_animation, Anim_Const(GetAnimationLength("grow", branches[branch].attach_slot)), branches[branch].attach_slot);
|
||||
else
|
||||
SetAnimationPosition(branches[branch].grow_animation, Anim_Linear(GetAnimationPosition(branches[branch].grow_animation,
|
||||
branches[branch].attach_slot),
|
||||
0,
|
||||
GetAnimationLength("grow", branches[branch].attach_slot),
|
||||
time,
|
||||
ANIM_Hold), branches[branch].attach_slot);
|
||||
}
|
||||
|
||||
// Called by the fruit before it flies off to give fair warning
|
||||
public func ShakeFruit(int branch)
|
||||
{
|
||||
var effect = AddEffect("IntShakeFruit", this, 1, 1, this);
|
||||
effect.branch = branch;
|
||||
}
|
||||
|
||||
private func FxIntShakeFruitTimer(object target, proplist effect, int time)
|
||||
{
|
||||
if (time > 24)
|
||||
return FX_Execute_Kill;
|
||||
var angle = Sin(time * 45, 4);
|
||||
SetAttachTransform(branches[effect.branch].fruit_slot, GetFruitAttachTransform(2000, angle));
|
||||
return FX_OK;
|
||||
}
|
||||
|
||||
// Called by the fruit
|
||||
// Returns the exit position of the fruit relative to the cotton plant
|
||||
// TODO: Do not hardcode positions but get the bone's position in Clonk coordinates (as of now feature is missing)
|
||||
public func GetFruitExitPosition(int branch)
|
||||
{
|
||||
if (branch == 0) return { x = 7 * direction, y = 0};
|
||||
if (branch == 1) return { x = -7 * direction, y = -1};
|
||||
if (branch == 2) return { x = 11 * direction, y = -16};
|
||||
return {}; // Unknown
|
||||
}
|
||||
|
||||
// Called by the fruit when it exits the plant
|
||||
// Will reverse the animation to full grown but not with fruit state in 35 frames
|
||||
// Accordingly, branches[].fruit will be cleared after 35 frames
|
||||
public func DetachFruit(int branch)
|
||||
{
|
||||
DetachMesh(branches[branch].fruit_slot);
|
||||
SetAnimationPosition(branches[branch].grow_animation, Anim_Linear(GetAnimationPosition(branches[branch].grow_animation,
|
||||
branches[branch].attach_slot),
|
||||
GetAnimationLength("grow",
|
||||
branches[branch].attach_slot),
|
||||
branches[branch].first_animation_stage,
|
||||
35,
|
||||
ANIM_Hold), branches[branch].attach_slot);
|
||||
ScheduleCall(this, "ClearFruit", 35, nil, branch);
|
||||
// This is to ensure that within the next 35 frames no new fruit will grow on this branch
|
||||
// This is necessary because the actual fruit object might be deleted before that time
|
||||
branches[branch].no_fruit = true;
|
||||
}
|
||||
|
||||
private func ClearFruit(int branch)
|
||||
{
|
||||
branches[branch].fruit = nil;
|
||||
branches[branch].fruit_slot = nil;
|
||||
branches[branch].no_fruit = nil;
|
||||
}
|
||||
|
||||
private func HasFruit()
|
||||
{
|
||||
for (var branch in branches)
|
||||
if (branch.fruit)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Crop Library */
|
||||
|
||||
public func SickleHarvesting()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Only harvestable if it has a ripe fruit
|
||||
public func IsHarvestable()
|
||||
{
|
||||
for (var branch in branches)
|
||||
if (branch.fruit)
|
||||
if (!branch.fruit->~IsGrowing())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public func Harvest(object clonk)
|
||||
{
|
||||
var fruit = -1;
|
||||
for (var i = 0; i < GetLength(branches); i++)
|
||||
if(branches[i].fruit)
|
||||
if(!branches[i].fruit->~IsGrowing())
|
||||
{
|
||||
fruit = i;
|
||||
break;
|
||||
}
|
||||
if (fruit == -1) return false;
|
||||
|
||||
branches[fruit].fruit->Fly();
|
||||
return true;
|
||||
}
|
||||
|
||||
/*-- Saving --*/
|
||||
|
||||
public func SaveScenarioObject(proplist props)
|
||||
{
|
||||
// The fruit are not saved if still inside, do a rudimentary save.
|
||||
// Saving all little details of growth is a bit too much for such an always changing state.
|
||||
for (var i = 0; i < GetLength(branches); i++)
|
||||
{
|
||||
// Branch has a fruit, save if grown
|
||||
if (branches[i].fruit)
|
||||
{
|
||||
if (!branches[i].fruit->IsGrowing())
|
||||
{
|
||||
props->AddCall("Branch", this, "GrowBranch", true, i);
|
||||
props->AddCall("Fruit", this, "GrowFruit", true);
|
||||
}
|
||||
else // If fruit is not fully grown, just save the branch
|
||||
props->AddCall("Branch", this, "GrowBranch", true, i);
|
||||
}
|
||||
else if (branches[i].grown) // Save only fully grown branches
|
||||
props->AddCall("Branch", this, "GrowBranch", true, i);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Definition */
|
||||
|
||||
local Name = "$Name$";
|
||||
local Description = "$Description$";
|
||||
local Collectible = 0;
|
||||
local growth = 3;
|
||||
local degrowth = -6;
|
||||
local fastgrowth = 9;
|
|
@ -0,0 +1,2 @@
|
|||
Name=Baumwolle
|
||||
Description=Eine fruchttragende Pflanze. Die Früchte enthalten Wolle, die zur Stoffproduktion verwendet werden kann.
|
|
@ -0,0 +1,2 @@
|
|||
Name=Cotton
|
||||
Description=A fruit bearing plant. The fruit contain wool that may be used to produce cloth.
|
After Width: | Height: | Size: 623 KiB |
|
@ -243,6 +243,17 @@ global func Particles_Straw()
|
|||
};
|
||||
}
|
||||
|
||||
global func Particles_CottonBalloon()
|
||||
{
|
||||
return
|
||||
{
|
||||
Prototype = Particles_WoodChip(),
|
||||
Phase = PV_Random(0, 3),
|
||||
Size = PV_Random(4, 8),
|
||||
Attach = nil
|
||||
};
|
||||
}
|
||||
|
||||
global func Particles_Air()
|
||||
{
|
||||
return
|
||||
|
|