File: Components.c

package info (click to toggle)
openclonk 8.1-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 169,656 kB
  • sloc: cpp: 180,484; ansic: 108,988; xml: 31,371; python: 1,223; php: 767; makefile: 148; sh: 101; javascript: 34
file content (130 lines) | stat: -rw-r--r-- 4,339 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
/**
	Components.c
	Handles the components of an object, which are a property of the object / definition.
	Components are a property of the form
		local Components = {Def1 = cnt1, Def2 = cnt2, ...};
	which can be modified directly or via the script functions in this file:
		SetComponent2(id component, int count)
		GetComponent(id component, int index)
		Split2Components()
		
	@author Maikel
*/


// Sets the component of an object or definition.
// documented in /docs/sdk/script/fn
global func SetComponent(id component, int count)
{
	// Safety: can only be called from object.
	if (!this || GetType(this) != C4V_C4Object)
		return FatalError(Format("SetComponent must be called from object context and not from %v", this));
		
	// Safety: component must be specified.
	if (!component || GetType(component) != C4V_Def)
		return FatalError(Format("First parameter (id component) of SetComponent must be a definition but was %v.", component));
		
	// Ensure count is non-negative.
	count = Max(count, 0);
	
	// Initialize Components if it does not exist yet.
	if (!this.Components || GetType(this.Components) != C4V_PropList)
		this.Components = {};
	// Ensure object property is different from definition property.
	if (this.Components == GetID().Components)
		MakePropertyWritable("Components");
	
	// Write the new count to the components properties.
	this.Components[Format("%i", component)] = count;
	return;
}

// Returns the amount if the component parameter is specified. If the component parameter is nil
// it returns the definition of the component for the given index.
// documented in /docs/sdk/script/fn
global func GetComponent(id component, int index)
{
	// Safety: can only be called from object or definition context.
	if (!this || (GetType(this) != C4V_C4Object && GetType(this) != C4V_Def))
		return FatalError(Format("GetComponent must be called from object or definition context and not from %v", this));

	// Safety: return nil if Components could not be found or are not a proplist.
	if (!this.Components || GetType(this.Components) != C4V_PropList)
		return;
		
	// If component is specified return the count for that definition.
	if (GetType(component) == C4V_Def)
		return this.Components[Format("%i", component)];

	// Ensure the index is valid.	
	index = Max(index, 0);

	// If component is not specified return the definition of the component at the index.
	var cnt = 0;
	for (var entry in GetProperties(this.Components))
	{
		// Check if the entry is an actual valid definition.
		var entry_def = GetDefinition(entry);
		if (!entry_def)
			continue;
		if (index == cnt)
			return entry_def;
		cnt++;
	}
	return;
}

// Callback by the engine when the completion of an object changes.
global func OnCompletionChange(int old_con, int new_con)
{
	if (!this || GetType(this) != C4V_C4Object)
		return _inherited(old_con, new_con, ...);
	
	// Determine whether the object allows Oversize.
	var oversize = GetDefCoreVal("Oversize", "DefCore");

	// Loop over all components and set their new count.
	var index = 0, comp;
	while (comp = GetID()->GetComponent(nil, index))
	{
		var def_cnt = GetID()->GetComponent(comp);
		var new_cnt = Max(def_cnt * new_con / 100000, 0);
		// If the object has no Oversize then constrain the maximum number of components.
		if (!oversize)
			new_cnt = Min(new_cnt, def_cnt);
		SetComponent(comp, new_cnt);
		index++;
	}
	return _inherited(old_con, new_con, ...);
}

// Splits the calling object into its components.
// documented in /docs/sdk/script/fn
global func Split2Components()
{
	// Safety: can only be called from object context.
	if (!this || GetType(this) != C4V_C4Object)
		return FatalError(Format("Split2Components must be called from object context and not from %v", this));

	// Transfer all contents to container.
	var ctr = Contained();
	while (Contents())
		if (!ctr || !Contents()->Enter(ctr))
			Contents()->Exit();
			
	// Split components.
	for (var i = 0, compid; compid = GetComponent(nil, i); ++i)
		for (var j = 0; j < GetComponent(compid); ++j)
		{
			var comp = CreateObjectAbove(compid, nil, nil, GetOwner());
			if (OnFire()) comp->Incinerate();
			if (!ctr || !comp->Enter(ctr))
			{
				comp->SetR(Random(360));
				comp->SetXDir(Random(3) - 1);
				comp->SetYDir(Random(3) - 1);
				comp->SetRDir(Random(3) - 1);
			}
		}
	return RemoveObject();
}