File: Script.c

package info (click to toggle)
openclonk 8.1-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 169,500 kB
  • sloc: cpp: 180,478; ansic: 108,988; xml: 31,371; python: 1,223; php: 767; makefile: 139; sh: 101; javascript: 34
file content (339 lines) | stat: -rw-r--r-- 7,537 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
/**
	Wooden Barrel
	The barrel is used to transport liquids
	
	@author: Ringwaul, ST-DDT
*/

#include Library_CarryHeavy
#include Library_LiquidContainer
#include Library_HasExtraSlot
#include Library_Flammable

/*-- Engine Callbacks --*/

func Initialize()
{
	AddTimer("Check", 5);
	UpdateLiquidContainer();
}

func RejectCollect(id def, object new_contents)
{
	// The barrel can only contain liquids.
	if (RejectStack(new_contents)) return true;
	return _inherited(def, new_contents, ...);
}

func Hit()
{
	this->PlayBarrelHitSound();
	if (Contents())
	{
		if (GBackLiquid(0, this.BarrelIntakeY)
		 && GetMaterial(0, this.BarrelIntakeY) != Contents()->GetLiquidType())
			return;

		EmptyBarrel(GetR());
		Sound("Liquids::Splash1");
	}
}

func PlayBarrelHitSound()
{
	Sound("Hits::Materials::Wood::DullWoodHit?");
}

public func Collection2(object item)
{
	UpdateLiquidContainer();
	return _inherited(item, ...);
}

public func Ejection(object item)
{
	UpdateLiquidContainer();
	return _inherited(item, ...);
}

public func ContentsDestruction(object item)
{
	ScheduleCall(this, "UpdateLiquidContainer", 1);
	return _inherited(item, ...);
}

public func RemoveLiquid(liquid_name, int amount, object destination)
{
	var res = _inherited(liquid_name, amount, destination, ...);
	UpdateLiquidContainer();
	return res;
}

public func PutLiquid(liquid_name, int amount, object source)
{
	var res = _inherited(liquid_name, amount, source, ...);
	UpdateLiquidContainer();
	return res;
}

/*-- Callbacks --*/

public func CollectFromStack(object item)
{
	// Callback from stackable object: Try grabbing partial objects from this stack, if the stack is too large
	if (item->GetStackCount() > GetLiquidAmountRemaining() && !this->RejectStack(item))
	{
		// Get one sample object and try to insert it into the barrel
		var candidate = item->TakeObject();
		candidate->Enter(this);
		
		// Put it back if it was not collected
		if (candidate && !(candidate->Contained()))
		{
			item->TryAddToStack(candidate);
		}
	}
}

public func RejectStack(object item)
{
	// Callback from stackable object: When should a stack entrance be rejected, if the object was not merged into the existing stacks?
	if (Contents())
	{
		// The barrel can hold only one type of liquid
		return true;
	}
	if (item->~IsLiquid() && this->~IsLiquidContainerForMaterial(item->~GetLiquidType()))
	{
		// The liquid is suitable, collect it!
		return false;
	}
	else
	{
		// Reject anything else
		return true;
	}
}

public func GetLiquidContainerMaxFillLevel(liquid_name)
{
	return 300;
}

public func IsBarrel()
{
	return true;
}

public func IsLiquidContainerForMaterial(string liquid_name)
{
	return !!WildcardMatch("Water", liquid_name) || !!WildcardMatch("Oil", liquid_name) || !!WildcardMatch("Concrete", liquid_name);
}

public func CanBeStackedWith(object other)
{
	// Does not take into account the fill level for now.
	var liquid = other->Contents();
	var my_liquid = this->Contents();
	var both_filled = (my_liquid != nil) && (liquid != nil);
	var both_empty = !my_liquid && !liquid;

	if (both_filled) both_filled = (liquid->~GetLiquidType() == Contents()->~GetLiquidType());
	
	return _inherited(other, ...) && (both_empty || both_filled);
}

// Sells the contents only, leaving an empty barrel.
// Empty barrels can then be sold separately.
public func QueryOnSell(int for_player, object in_base)
{
	if (Contents() && in_base)
	{
		// Sell contents first
		for(var contents in FindObjects(Find_Container(this)))
		{
			in_base->~DoSell(contents, for_player);
		}
		return true;
	}
	return false;
}

/*-- Usage --*/

public func ControlUse(object clonk, int iX, int iY)
{
	var AimAngle = Angle(0, 0, iX, iY);
	if (Contents())
	{
		EmptyBarrel(AimAngle, 50, clonk);
		if (iX > 1)
			Contained()->SetDir(1);
		if (iX < -1)
			Contained()->SetDir(0);
	}
	return true;
}

func Check()
{
	//Fills Barrel with specified liquid from if submerged
	FillWithLiquid();
	
	//Message("Volume:|%d|Liquid:|%s", iVolume, szLiquid);
}

func FillWithLiquid()
{
	var intake = this.BarrelIntakeY;
	if (!GBackLiquid(0, intake)) return;
	if (GetLiquidAmount() >= GetLiquidContainerMaxFillLevel()) return;
	
	var mat = GetMaterial(0, intake);
	var mat_name = MaterialName(mat);
	if (!IsLiquidContainerForMaterial(mat_name)) return;

	var remaining_volume = GetLiquidContainerMaxFillLevel() - GetLiquidAmount();
	var extracted = 0;
	while (extracted < remaining_volume && GetMaterial(0, intake) == mat)
	{
		extracted += 1;
		ExtractLiquid(0, intake);
	}
	
	var inserted = 0;
	if (extracted > 0) inserted = PutLiquid(mat_name, extracted);

	if (inserted < extracted)
	{
		CastPXS(mat_name, extracted - inserted, 1, 0, intake);
	}
}

func EmptyBarrel(int angle, int strength, object clonk)
{
	if (Contents())
	{
		var material = Contents()->~GetLiquidType();
		var volume = Contents()->~GetLiquidAmount();
	
		Contents()->~Disperse(angle, strength);

		var spray = {};
		spray.Liquid = material;
		spray.Volume = volume;
		spray.Strength = strength;
		spray.Angle = angle;
		spray.Clonk = clonk;
		AddEffect("ExtinguishingSpray", clonk, 100, 1, this, nil, spray);

		UpdateLiquidContainer();
	}
}

func UpdateLiquidContainer()
{
	if (Contents())
	{
		var color;
		var material = Material(Contents()->GetLiquidType());
		if (material >= 0)
		{
			var tex = GetMaterialVal("TextureOverlay", "Material", material);
			color = GetAverageTextureColor(tex);
		}
		else
		{
			color = RGB(0, 0, 0);
		}
		SetColor(color);
	}
	else
	{
		SetColor(RGB(0, 0, 0));
	}

	this.Name = GetNameForBarrel();
	return;
}

func FxExtinguishingSprayStart(object target, proplist effect, int temp, proplist spray)
{
	if (temp)
		return FX_OK;
	// Only for extinguishing materials.	
	if (!GetMaterialVal("Extinguisher", "Material",	Material(spray.Liquid)))
		return FX_Start_Deny;		
	// If used by an object also extinguish that.
	if (spray.Clonk)
		spray.Clonk->Extinguish(Min(100, spray.Volume/3));
	// Store spray parameters.	
	effect.Volume = spray.Volume;
	effect.Strength = spray.Strength;
	effect.Angle = spray.Angle;
	return FX_OK;
}

func FxExtinguishingSprayTimer(object target, proplist effect, int time)
{
	// Move three lines from the barrel outwards along the defined angle.
	// And extinguish all objects on these lines.
	if (time > 20)
		return FX_Execute_Kill;
	var d = effect.Strength * time / 25;
	for (var dev = -10; dev <= 10; dev+= 10)
	{ 
		var x = Sin(effect.Angle + dev, d);
		var y = -Cos(effect.Angle + dev, d);
		if (PathFree(GetX(), GetY(), GetX() + x, GetY() + y))
			for (var obj in FindObjects(Find_AtPoint(x, y), Find_OCF(OCF_OnFire)))
				obj->Extinguish(Max(0, effect.Volume/3 - 2 * d));
	}
	return FX_OK;
}

/*-- Production --*/

public func IsToolProduct() { return true; }

/*-- Display --*/

public func GetCarryTransform(clonk)
{
	if(GetCarrySpecial(clonk))
		return Trans_Translate(1000, 6500, 0);
	
	return Trans_Translate(1500, 0, -1500);
}

public func GetCarryPhase()
{
	return 900;
}

public func Definition(proplist def)
{
	SetProperty("PictureTransformation", Trans_Mul(Trans_Translate(0, 1000, 0), Trans_Rotate(-40, 1, 0, 0), Trans_Rotate(20, 0, 0, 1)), def);
}

/*-- Properties --*/

func GetNameForBarrel()
{
	if (Contents())
	{
		var name = Format("%s $NameWith$ %s", this.Prototype.Name, Contents().Prototype.Name);
		return name;
	}
	else
	{
		return this.Prototype.Name;
	}
}

local Name = "$Name$";
local Description = "$Description$";
local Collectible = true;
local ContactIncinerate = 2;
local BarrelIntakeY = 3;
local Components = {Wood = 2, Metal = 1};