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 (325 lines) | stat: -rw-r--r-- 8,961 bytes parent folder | download | duplicates (7)
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
/**
	Scoreboard
	Provides an additional abstraction layer on top of the scoreboard-functions
	
	Attention: Do not include this. Use the function as specified with f.e. Scoreboard->Init(...)
*/

// do not manipulate externally
static Scoreboard_keys; // [{key = ?, title = ?, ..}, ..]
static Scoreboard_data; // [{key = value, ..}, ..]
static Scoreboard_unique_ids;
static Scoreboard_title_set;

static const Scoreboard_Y_title = SBRD_Caption;
static const Scoreboard_X_title = SBRD_Caption;

// wrapper for Scoreboard->NewEntry, adds a new entry for a player with the tagged player name as the title
public func NewPlayerEntry(int plr)
{
	return Scoreboard->NewEntry(GetPlayerID(plr), GetTaggedPlayerName(plr));
}

public func RemovePlayerEntry(int plr)
{
	return Scoreboard->RemoveEntry(GetPlayerID(plr));
}

// adds a new entry (row) to the scoreboard, will return the ID of the added entry
// the parameter new_id might be nil in which case a unique new ID is chosen
public func NewEntry(
	int new_id /* unique ID for the new entry, can be nil */
	, string new_title /* text for the first column */
	)
{
	// not initialized yet? Then init empty.
	if (!Scoreboard_keys) Init([]);
	// check for duplicates
	if(new_id)
	{
		var index = -1;
		for(var i = 0; i < GetLength(Scoreboard_data); ++i)
		{
			if(Scoreboard_data[i].ID != new_id) continue;
			index = i;
			break;
		}
		
		// duplicate?
		if(index != -1) return nil;
	}
	else // no ID provided, get new one
	{
		new_id = ++Scoreboard_unique_ids;
	}
	
	PushBack(Scoreboard_data, {ID = new_id, title = new_title});
	Scoreboard->Update(new_id);
	return new_id;
}

// removes an entry (row) from the scoreboard
public func RemoveEntry(
	int remove_id /* unique ID for the new entry, can be nil */
	)
{
	var i, len = GetLength(Scoreboard_data);
	for(i = 0; i < len; ++i) if(Scoreboard_data[i].ID == remove_id) break;
	if (i == len) return false; // not found
	RemoveArrayIndex(Scoreboard_data, i);
	// Clear all columns
	for (var col in Scoreboard_keys) SetScoreboardData(remove_id, col.index);
	SetScoreboardData(remove_id, Scoreboard_X_title);
	return true;
}

// sets a value for a specific key of a scoreboard entry for a player and updates it
// that entry must have been created earlier with ScoreboarNewPlayerEntry or manually with Scoreboard->NewEntry
public func SetPlayerData(
	int plr /* player number for the player entry to manipulate */
	, string key /* name of the key assign value to */
	, to /* value to assign, might be ID, string, int or bool */
	, int sort_parameter /* parameter used for sorting. if nil, 'to' is used if possible*/
	)
{
	var ID = GetPlayerID(plr);
	return Scoreboard->SetData(ID, key, to, sort_parameter);
}

// sets a value for a specific key of any entry in the scoreboard and updates it
// the entry must have been created with Scoreboard->NewEntry earlier
public func SetData(
	int ID /* ID of the entry to manipulate */
	, string key /* name of the key to assign value to */
	, to /* new value of the key, might be int, string bool or id */
	, int sort_parameter /* parameter that is used for sorting of the entry. if nil, 'to' is used if possible*/
	)
{
	var index = -1;
	for(var i = 0; i < GetLength(Scoreboard_data); ++i)
	{
		if(Scoreboard_data[i].ID != ID) continue;
		index = i;
		break;
	}
	if(index == -1) return;
	
	Scoreboard_data[i][key] = to;
	if(sort_parameter)
		Scoreboard_data[i][Format("%s_", key)] = sort_parameter;
	Scoreboard->Update(ID);
}

// updates the display of the scoreboard
// there is usually no need to call it manually since Scoreboard->SetData calls Update
public func Update(
	int ID /* ID of the entry to update */
	, int index /* optional, internal index. leave at nil.*/
	)
{
	if(index == nil)
	{
		for(var i = 0; i < GetLength(Scoreboard_data); ++i)
		{
			if(Scoreboard_data[i].ID != ID) continue;
			index = i;
			break;
		}
		if(index == nil) return;
	}
	
	var data = Scoreboard_data[index];
	
	// title - playername f.e.
	SetScoreboardData(data.ID, Scoreboard_X_title, data.title, -1);
	
	var len = GetLength(Scoreboard_keys);
	for(var i = 0; i < len; ++i)
	{
		var col = Scoreboard_keys[i];
		if(!col.key) continue;
		if(col.key == "title") continue; // already set
		
		// aquire value
		var value = col.default;
		if(data[col.key] != nil) value = data[col.key];
		
		// get sorting parameter
		var sort = data[Format("%s_", col.key)];
		if(sort == nil)
			if(GetType(value) == C4V_Int) sort = value;
		
		// the column provides a conditional function
		if(col.conditional)
		{
			value = col->conditional(value);
			
			// overwrite old sort?
			if(GetType(value) == C4V_Int) sort = value;
		}
		
		if(value == nil) value = "";
		else if(GetType(value) == C4V_Int) {value = Format("%d", value);}
		else if(GetType(value) == C4V_Def) value = Format("{{%i}}", value);
		else if(GetType(value) == C4V_Bool) {sort = value; if(value) value = "X"; else value = "";}

		SetScoreboardData(data.ID, col.index, value, sort);
	}
	UpdateSort();
	return true;
}

public func UpdateSort()
{
	// do sorting for fields neccessary
	var len = GetLength(Scoreboard_keys);
	for(var i = len-1; i >= 0; --i)
	{
		var col = Scoreboard_keys[i];
		if(!col.key) continue;
		if(!col.sorted) continue;
		
		SortScoreboard(col.index, col.desc);
	}
	return true;
}

// updates the whole scoreboard
public func UpdateAll()
{
	// for every row, do update
	var len = GetLength(Scoreboard_data);
	for(var i = 0; i < len; ++i)
	{
		Scoreboard->Update(Scoreboard_data[i].ID, i);
	}
	return true;
}

// remove a column from the scoreboard
public func RemoveColumn(string key)
{
	var col, data;
	if (!key) FatalError("Scoreboard::RemoveColumn: Key required!");
	// find key
	for (col in Scoreboard_keys) if (col.key == key) break;
	if (!col || col.key != key) return false; // key not found. fail but not fatal.
	// for every row, remove data for key
	for (data in Scoreboard_data)
	{
		data[key] = data[Format("%s_", key)] = nil;
		SetScoreboardData(data.ID, col.index);
	}
	// resort
	SortScoreboard(col.index, col.desc);
	return true;
}

// initializes the scoreboard with certain columns and attributes
// can be called multiple times and scales
// values must be an array of proplists where each entry stands for one column
// the entries can have the following attributes:
// "key" is required and used later for Scoreboard->SetData
// {key (string), priority (int), sorted (bool), desc (bool), title (string), default (any)}
// one row with key = "title" is necessary and will be automatically added if left out and not existent
public func Init(array values /* see description */)
{
	// first call?
	if(Scoreboard_unique_ids == nil)
	{
		Scoreboard_unique_ids = 0xffffff;
		Scoreboard_keys = [];
		Scoreboard_data = [];
		
		if(!Scoreboard_title_set)
			Scoreboard->SetTitle("Scoreboard");
	}
	
	// merge arrays
	for(var val in values)
	{
		if(val == nil) continue;
		
		var index = nil;
		for(var i = GetLength(Scoreboard_keys)-1; i >= 0; --i)
		{
			if(Scoreboard_keys[i].key != val.key) continue;
			index = i;
			break;
		}
		if(index == nil)
			PushBack(Scoreboard_keys, val); // new entry
		else Scoreboard_keys[index] = val; // overwrite
	}
	
	// title property set?
	var found_title = false;
	for(var col in Scoreboard_keys)
	{
		if(col.key != "title") continue;
		found_title = true;
		break;
	}
	
	// if not, add
	if(!found_title)
		PushBack(Scoreboard_keys, {key = "title", title = ""});
	
	
	// sort, selection sort
	var len = GetLength(Scoreboard_keys);
	for(var x = 0; x < len - 1; ++x)
	{
		var max = -1, max_val = nil;
		for(var i = x; i < len; ++i)
		{
			var data = Scoreboard_keys[i]; 
			if(max_val == nil || (data.priority > max_val))
			{
				max = i;
				max_val = data.priority;
			}
		}
		if(max == -1) break;
		
		var t = Scoreboard_keys[x];
		Scoreboard_keys[x] = Scoreboard_keys[max];
		Scoreboard_keys[max] = t;
	}
	
	// assign indices to scoreboard data, they are now sorted - also create scoreboard
	var len = GetLength(Scoreboard_keys);
	for(var i = 0; i < len; ++i)
	{
		Scoreboard_keys[i].index = i;
		
		if(Scoreboard_keys[i].key == "title") // title has special index and no headline
		{
			Scoreboard_keys[i].index = Scoreboard_X_title;
			// don't set headline for title (first) column, because that would change the scoreboard title
			continue;
		}
		
		// check title
		if(GetType(Scoreboard_keys[i].title) == C4V_Def)
			Scoreboard_keys[i].title = Format("{{%i}}", Scoreboard_keys[i].title);
					
		var data = -0xffffff;
		if(Scoreboard_keys[i].desc) data = 0xffffff;
		SetScoreboardData(Scoreboard_Y_title, Scoreboard_keys[i].index, Scoreboard_keys[i].title, data);
	}
	
	
	// setup scoreboard
	Scoreboard->UpdateAll();
	
	// show scoreboard, only initially - after that it's the player's choice
	DoScoreboardShow(1); 
}

// sets the title of the scoreboard, standard is "Scoreboard"
public func SetTitle(string title)
{
	SetScoreboardData(SBRD_Caption, SBRD_Caption, title);
	Scoreboard_title_set = true;
}