1 //       _________ __                 __
2 //      /   _____//  |_____________ _/  |______     ____  __ __  ______
3 //      \_____  \\   __\_  __ \__  \\   __\__  \   / ___\|  |  \/  ___/
4 //      /        \|  |  |  | \// __ \|  |  / __ \_/ /_/  >  |  /\___ |
5 //     /_______  /|__|  |__|  (____  /__| (____  /\___  /|____//____  >
6 //             \/                  \/          \//_____/            \/
7 //  ______________________                           ______________________
8 //                        T H E   W A R   B E G I N S
9 //         Stratagus - A free fantasy real time strategy game engine
10 //
11 /**@name contenttype.cpp - . */
12 //
13 //      (c) Copyright 1999-2015 by Joris Dauphin and Andrettin
14 //
15 //      This program is free software; you can redistribute it and/or modify
16 //      it under the terms of the GNU General Public License as published by
17 //      the Free Software Foundation; only version 2 of the License.
18 //
19 //      This program is distributed in the hope that it will be useful,
20 //      but WITHOUT ANY WARRANTY; without even the implied warranty of
21 //      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 //      GNU General Public License for more details.
23 //
24 //      You should have received a copy of the GNU General Public License
25 //      along with this program; if not, write to the Free Software
26 //      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 //      02111-1307, USA.
28 //
29 
30 //@{
31 
32 /*----------------------------------------------------------------------------
33 --  Includes
34 ----------------------------------------------------------------------------*/
35 
36 #include "stratagus.h"
37 
38 #include "ui/contenttype.h"
39 
40 #include "actions.h"
41 #include "action/action_built.h"
42 #include "font.h"
43 #include "translate.h"
44 #include "unit.h"
45 #include "ui.h"
46 #include "video.h"
47 
48 enum UStrIntType {
49 	USTRINT_STR, USTRINT_INT
50 };
51 struct UStrInt {
52 	union {const char *s; int i;};
53 	UStrIntType type;
54 };
55 
56 extern UStrInt GetComponent(const CUnit &unit, int index, EnumVariable e, int t);
57 extern UStrInt GetComponent(const CUnitType &type, int index, EnumVariable e);
58 
~CContentType()59 /* virtual */ CContentType::~CContentType()
60 {
61 	delete Condition;
62 }
63 
64 /**
65 **  Draw text with variable.
66 **
67 **  @param unit         unit with variable to show.
68 **  @param defaultfont  default font if no specific font in extra data.
69 */
Draw(const CUnit & unit,CFont * defaultfont) const70 /* virtual */ void CContentTypeText::Draw(const CUnit &unit, CFont *defaultfont) const
71 {
72 	std::string text;       // Optional text to display.
73 	int x = this->Pos.x;
74 	int y = this->Pos.y;
75 	CFont &font = this->Font ? *this->Font : *defaultfont;
76 
77 	Assert(&font);
78 	Assert(this->Index == -1 || ((unsigned int) this->Index < UnitTypeVar.GetNumberVariable()));
79 
80 	CLabel label(font);
81 
82 	if (this->Text) {
83 		text = EvalString(this->Text);
84 		std::string::size_type pos;
85 		if ((pos = text.find("~|")) != std::string::npos) {
86 			x += (label.Draw(x - font.getWidth(text.substr(0, pos)), y, text) - font.getWidth(text.substr(0, pos)));
87 		} else if (this->Centered) {
88 			x += (label.DrawCentered(x, y, text) * 2);
89 		} else {
90 			x += label.Draw(x, y, text);
91 		}
92 	}
93 
94 	if (this->ShowName) {
95 		label.DrawCentered(x, y, unit.Type->Name);
96 		return;
97 	}
98 
99 	if (this->Index != -1) {
100 		if (!this->Stat) {
101 			EnumVariable component = this->Component;
102 			switch (component) {
103 				case VariableValue:
104 				case VariableMax:
105 				case VariableIncrease:
106 				case VariableDiff:
107 				case VariablePercent:
108 					label.Draw(x, y, GetComponent(unit, this->Index, component, 0).i);
109 					break;
110 				case VariableName:
111 					label.Draw(x, y, GetComponent(unit, this->Index, component, 0).s);
112 					break;
113 				default:
114 					Assert(0);
115 			}
116 		} else {
117 			int value = unit.Type->MapDefaultStat.Variables[this->Index].Value;
118 			int diff = unit.Stats->Variables[this->Index].Value - value;
119 
120 			if (!diff) {
121 				label.Draw(x, y, value);
122 			} else {
123 				char buf[64];
124 				snprintf(buf, sizeof(buf), diff > 0 ? "%d~<+%d~>" : "%d~<-%d~>", value, diff);
125 				label.Draw(x, y, buf);
126 			}
127 		}
128 	}
129 }
130 
131 /**
132 **  Draw formatted text with variable value.
133 **
134 **  @param unit         unit with variable to show.
135 **  @param defaultfont  default font if no specific font in extra data.
136 **
137 **  @note text is limited to 256 chars. (enough?)
138 **  @note text must have exactly 1 %d.
139 **  @bug if text format is incorrect.
140 */
Draw(const CUnit & unit,CFont * defaultfont) const141 /* virtual */ void CContentTypeFormattedText::Draw(const CUnit &unit, CFont *defaultfont) const
142 {
143 	char buf[256];
144 	UStrInt usi1;
145 
146 	CFont &font = this->Font ? *this->Font : *defaultfont;
147 	Assert(&font);
148 
149 	CLabel label(font);
150 
151 	Assert((unsigned int) this->Index < UnitTypeVar.GetNumberVariable());
152 	usi1 = GetComponent(unit, this->Index, this->Component, 0);
153 	if (usi1.type == USTRINT_STR) {
154 		snprintf(buf, sizeof(buf), this->Format.c_str(), _(usi1.s));
155 	} else {
156 		snprintf(buf, sizeof(buf), this->Format.c_str(), usi1.i);
157 	}
158 
159 	char *pos;
160 	if ((pos = strstr(buf, "~|")) != NULL) {
161 		std::string buf2(buf);
162 		label.Draw(this->Pos.x - font.getWidth(buf2.substr(0, pos - buf)), this->Pos.y, buf);
163 	} else if (this->Centered) {
164 		label.DrawCentered(this->Pos.x, this->Pos.y, buf);
165 	} else {
166 		label.Draw(this->Pos.x, this->Pos.y, buf);
167 	}
168 }
169 
170 /**
171 **  Draw formatted text with variable value.
172 **
173 **  @param unit         unit with variable to show.
174 **  @param defaultfont  default font if no specific font in extra data.
175 **
176 **  @note text is limited to 256 chars. (enough?)
177 **  @note text must have exactly 2 %d.
178 **  @bug if text format is incorrect.
179 */
Draw(const CUnit & unit,CFont * defaultfont) const180 /* virtual */ void CContentTypeFormattedText2::Draw(const CUnit &unit, CFont *defaultfont) const
181 {
182 	char buf[256];
183 	UStrInt usi1, usi2;
184 
185 	CFont &font = this->Font ? *this->Font : *defaultfont;
186 	Assert(&font);
187 	CLabel label(font);
188 
189 	usi1 = GetComponent(unit, this->Index1, this->Component1, 0);
190 	usi2 = GetComponent(unit, this->Index2, this->Component2, 0);
191 	if (usi1.type == USTRINT_STR) {
192 		if (usi2.type == USTRINT_STR) {
193 			snprintf(buf, sizeof(buf), this->Format.c_str(), _(usi1.s), _(usi2.s));
194 		} else {
195 			snprintf(buf, sizeof(buf), this->Format.c_str(), _(usi1.s), usi2.i);
196 		}
197 	} else {
198 		if (usi2.type == USTRINT_STR) {
199 			snprintf(buf, sizeof(buf), this->Format.c_str(), usi1.i, _(usi2.s));
200 		} else {
201 			snprintf(buf, sizeof(buf), this->Format.c_str(), usi1.i, usi2.i);
202 		}
203 	}
204 	char *pos;
205 	if ((pos = strstr(buf, "~|")) != NULL) {
206 		std::string buf2(buf);
207 		label.Draw(this->Pos.x - font.getWidth(buf2.substr(0, pos - buf)), this->Pos.y, buf);
208 	} else if (this->Centered) {
209 		label.DrawCentered(this->Pos.x, this->Pos.y, buf);
210 	} else {
211 		label.Draw(this->Pos.x, this->Pos.y, buf);
212 	}
213 }
214 
215 
216 /**
217 **  Get unit from a unit depending of the relation.
218 **
219 **  @param unit  unit reference.
220 **  @param e     relation with unit.
221 **
222 **  @return      The desired unit.
223 */
GetUnitRef(const CUnit & unit,EnumUnit e)224 static const CUnit *GetUnitRef(const CUnit &unit, EnumUnit e)
225 {
226 	switch (e) {
227 		case UnitRefItSelf:
228 			return &unit;
229 		case UnitRefInside:
230 			return unit.UnitInside;
231 		case UnitRefContainer:
232 			return unit.Container;
233 		case UnitRefWorker :
234 			if (unit.CurrentAction() == UnitActionBuilt) {
235 				COrder_Built &order = *static_cast<COrder_Built *>(unit.CurrentOrder());
236 
237 				return order.GetWorkerPtr();
238 			} else {
239 				return NULL;
240 			}
241 		case UnitRefGoal:
242 			return unit.Goal;
243 		default:
244 			Assert(0);
245 	}
246 	return NULL;
247 }
248 
249 /**
250 **  Draw icon for unit.
251 **
252 **  @param unit         unit with icon to show.
253 **  @param defaultfont  unused.
254 */
Draw(const CUnit & unit,CFont *) const255 /* virtual */ void CContentTypeIcon::Draw(const CUnit &unit, CFont *) const
256 {
257 	const CUnit *unitToDraw = GetUnitRef(unit, this->UnitRef);
258 
259 	if (unitToDraw && unitToDraw->Type->Icon.Icon) {
260 		unitToDraw->Type->Icon.Icon->DrawUnitIcon(*UI.SingleSelectedButton->Style, 0, this->Pos, "",
261 			unitToDraw->RescuedFrom ? unitToDraw->RescuedFrom->Index : unitToDraw->Player->Index);
262 	}
263 }
264 
265 /**
266 **  Draw life bar of a unit using selected variable.
267 **  Placed under icons on top-panel.
268 **
269 **  @param unit         Pointer to unit.
270 **  @param defaultfont  FIXME: docu
271 **
272 **  @todo Color and percent value Parametrisation.
273 */
Draw(const CUnit & unit,CFont *) const274 /* virtual */ void CContentTypeLifeBar::Draw(const CUnit &unit, CFont *) const
275 {
276 	Uint32 color;
277 	int f;
278 	if (this->Index != -1) {
279 		Assert((unsigned int) this->Index < UnitTypeVar.GetNumberVariable());
280 		if (!unit.Variable[this->Index].Max) {
281 			return;
282 		}
283 		f = (100 * unit.Variable[this->Index].Value) / unit.Variable[this->Index].Max;
284 	} else {
285 		f = (100 * EvalNumber(this->ValueFunc)) / this->ValueMax;
286 		f = f > 100 ? 100 : f;
287 		if (f < 0) {
288 			return;
289 		}
290 	}
291 	int i = 0;
292 
293 	// get to right color
294 	while (f < this->values[i]) {
295 		i++;
296 	}
297 	color = IndexToColor(this->colors[i]);
298 
299 	if (this->hasBorder) {
300 		// Border. We have a simple heuristic to determine how big it is...
301 		// TODO: make configurable?
302 		if (this->Height <= 6) {
303 			Video.FillRectangleClip(this->hasBorder, this->Pos.x - 2, this->Pos.y - 2,
304 									this->Width + 2, this->Height + 2);
305 		} else {
306 			Video.FillRectangleClip(this->hasBorder, this->Pos.x - 2, this->Pos.y - 2,
307 									this->Width + 3, this->Height + 3);
308 		}
309 	}
310 
311 	Video.FillRectangleClip(color, this->Pos.x - 1, this->Pos.y - 1,
312 							(f * this->Width) / 100, this->Height);
313 }
314 
315 /**
316 **  Draw life bar of a unit using selected variable.
317 **  Placed under icons on top-panel.
318 **
319 **  @param unit         Pointer to unit.
320 **  @param defaultfont  FIXME: docu
321 **
322 **  @todo Color and percent value Parametrisation.
323 */
Draw(const CUnit & unit,CFont *) const324 /* virtual */ void CContentTypeCompleteBar::Draw(const CUnit &unit, CFont *) const
325 {
326 	Assert((unsigned int) this->varIndex < UnitTypeVar.GetNumberVariable());
327 	if (!unit.Variable[this->varIndex].Max) {
328 		return;
329 	}
330 	int x = this->Pos.x;
331 	int y = this->Pos.y;
332 	int w = this->width;
333 	int h = this->height;
334 	Assert(w > 0);
335 	Assert(h > 4);
336 	const Uint32 color = (colorIndex != -1) ? IndexToColor(colorIndex) : UI.CompletedBarColor;
337 	const int f = (100 * unit.Variable[this->varIndex].Value) / unit.Variable[this->varIndex].Max;
338 
339 	if (!this->hasBorder) {
340 		Video.FillRectangleClip(color, x, y, f * w / 100, h);
341 		if (UI.CompletedBarShadow) {
342 			// Shadow
343 			Video.DrawVLine(ColorGray, x + f * w / 100, y, h);
344 			Video.DrawHLine(ColorGray, x, y + h, f * w / 100);
345 
346 			// |~  Light
347 			Video.DrawVLine(ColorWhite, x, y, h);
348 			Video.DrawHLine(ColorWhite, x, y, f * w / 100);
349 		}
350 	} else {
351 		Video.DrawRectangleClip(ColorWhite,  x,     y,     w + 4, h);
352 		Video.DrawRectangleClip(ColorBlack, x + 1, y + 1, w + 2, h - 2);
353 		Video.FillRectangleClip(color, x + 2, y + 2, f * w / 100, h - 4);
354 	}
355 }
356 
Parse(lua_State * l)357 /* virtual */ void CContentTypeText::Parse(lua_State *l)
358 {
359 	Assert(lua_istable(l, -1) || lua_isstring(l, -1));
360 
361 	if (lua_isstring(l, -1)) {
362 		this->Text = CclParseStringDesc(l);
363 		lua_pushnil(l); // ParseStringDesc eat token
364 	} else {
365 		for (lua_pushnil(l); lua_next(l, -2); lua_pop(l, 1)) {
366 			const char *key = LuaToString(l, -2);
367 			if (!strcmp(key, "Text")) {
368 				this->Text = CclParseStringDesc(l);
369 				lua_pushnil(l); // ParseStringDesc eat token
370 			} else if (!strcmp(key, "Font")) {
371 				this->Font = CFont::Get(LuaToString(l, -1));
372 			} else if (!strcmp(key, "Centered")) {
373 				this->Centered = LuaToBoolean(l, -1);
374 			} else if (!strcmp(key, "Variable")) {
375 				const char *const name = LuaToString(l, -1);
376 				this->Index = UnitTypeVar.VariableNameLookup[name];
377 				if (this->Index == -1) {
378 					LuaError(l, "unknown variable '%s'" _C_ LuaToString(l, -1));
379 				}
380 			} else if (!strcmp(key, "Component")) {
381 				this->Component = Str2EnumVariable(l, LuaToString(l, -1));
382 			} else if (!strcmp(key, "Stat")) {
383 				this->Stat = LuaToBoolean(l, -1);
384 			} else if (!strcmp(key, "ShowName")) {
385 				this->ShowName = LuaToBoolean(l, -1);
386 			} else {
387 				LuaError(l, "'%s' invalid for method 'Text' in DefinePanelContents" _C_ key);
388 			}
389 		}
390 	}
391 }
392 
Parse(lua_State * l)393 /* virtual */ void CContentTypeFormattedText::Parse(lua_State *l)
394 {
395 	Assert(lua_istable(l, -1));
396 
397 	for (lua_pushnil(l); lua_next(l, -2); lua_pop(l, 1)) {
398 		const char *key = LuaToString(l, -2);
399 		if (!strcmp(key, "Format")) {
400 			this->Format = LuaToString(l, -1);
401 		} else if (!strcmp(key, "Font")) {
402 			this->Font = CFont::Get(LuaToString(l, -1));
403 		} else if (!strcmp(key, "Variable")) {
404 			const char *const name = LuaToString(l, -1);
405 			this->Index = UnitTypeVar.VariableNameLookup[name];
406 			if (this->Index == -1) {
407 				LuaError(l, "unknown variable '%s'" _C_ name);
408 			}
409 		} else if (!strcmp(key, "Component")) {
410 			this->Component = Str2EnumVariable(l, LuaToString(l, -1));
411 		} else if (!strcmp(key, "Centered")) {
412 			this->Centered = LuaToBoolean(l, -1);
413 		} else {
414 			LuaError(l, "'%s' invalid for method 'FormattedText' in DefinePanelContents" _C_ key);
415 		}
416 	}
417 }
418 
Parse(lua_State * l)419 /* virtual */ void CContentTypeFormattedText2::Parse(lua_State *l)
420 {
421 	Assert(lua_istable(l, -1));
422 	for (lua_pushnil(l); lua_next(l, -2); lua_pop(l, 1)) {
423 		const char *key = LuaToString(l, -2);
424 		if (!strcmp(key, "Format")) {
425 			this->Format = LuaToString(l, -1);
426 		} else if (!strcmp(key, "Font")) {
427 			this->Font = CFont::Get(LuaToString(l, -1));
428 		} else if (!strcmp(key, "Variable")) {
429 			const char *const name = LuaToString(l, -1);
430 			this->Index1 = UnitTypeVar.VariableNameLookup[name];
431 			this->Index2 = this->Index1;
432 			if (this->Index1 == -1) {
433 				LuaError(l, "unknown variable '%s'" _C_ name);
434 			}
435 		} else if (!strcmp(key, "Component")) {
436 			this->Component1 = Str2EnumVariable(l, LuaToString(l, -1));
437 			this->Component2 = Str2EnumVariable(l, LuaToString(l, -1));
438 		} else if (!strcmp(key, "Variable1")) {
439 			const char *const name = LuaToString(l, -1);
440 			this->Index1 = UnitTypeVar.VariableNameLookup[name];
441 			if (this->Index1 == -1) {
442 				LuaError(l, "unknown variable '%s'" _C_ name);
443 			}
444 		} else if (!strcmp(key, "Component1")) {
445 			this->Component1 = Str2EnumVariable(l, LuaToString(l, -1));
446 		} else if (!strcmp(key, "Variable2")) {
447 			const char *const name = LuaToString(l, -1);
448 			this->Index2 = UnitTypeVar.VariableNameLookup[name];
449 			if (this->Index2 == -1) {
450 				LuaError(l, "unknown variable '%s'" _C_ LuaToString(l, -1));
451 			}
452 		} else if (!strcmp(key, "Component2")) {
453 			this->Component2 = Str2EnumVariable(l, LuaToString(l, -1));
454 		} else if (!strcmp(key, "Centered")) {
455 			this->Centered = LuaToBoolean(l, -1);
456 		} else {
457 			LuaError(l, "'%s' invalid for method 'FormattedText2' in DefinePanelContents" _C_ key);
458 		}
459 	}
460 }
461 
462 /**
463 **  Return enum from string about variable component.
464 **
465 **  @param l Lua State.
466 **  @param s string to convert.
467 **
468 **  @return  Corresponding value.
469 **  @note    Stop on error.
470 */
Str2EnumUnit(lua_State * l,const char * s)471 static EnumUnit Str2EnumUnit(lua_State *l, const char *s)
472 {
473 	static struct {
474 		const char *s;
475 		EnumUnit e;
476 	} list[] = {
477 		{"ItSelf", UnitRefItSelf},
478 		{"Inside", UnitRefInside},
479 		{"Container", UnitRefContainer},
480 		{"Worker", UnitRefWorker},
481 		{"Goal", UnitRefGoal},
482 		{0, UnitRefItSelf}
483 	}; // List of possible values.
484 
485 	for (int i = 0; list[i].s; ++i) {
486 		if (!strcmp(s, list[i].s)) {
487 			return list[i].e;
488 		}
489 	}
490 	LuaError(l, "'%s' is a invalid Unit reference" _C_ s);
491 	return UnitRefItSelf;
492 }
493 
Parse(lua_State * l)494 /* virtual */ void CContentTypeIcon::Parse(lua_State *l)
495 {
496 	for (lua_pushnil(l); lua_next(l, -2); lua_pop(l, 1)) {
497 		const char *key = LuaToString(l, -2);
498 		if (!strcmp(key, "Unit")) {
499 			this->UnitRef = Str2EnumUnit(l, LuaToString(l, -1));
500 		} else {
501 			LuaError(l, "'%s' invalid for method 'Icon' in DefinePanelContents" _C_ key);
502 		}
503 	}
504 }
505 
Parse(lua_State * l)506 /* virtual */ void CContentTypeLifeBar::Parse(lua_State *l)
507 {
508 	for (lua_pushnil(l); lua_next(l, -2); lua_pop(l, 1)) {
509 		const char *key = LuaToString(l, -2);
510 		if (!strcmp(key, "Variable")) {
511 			if (lua_isstring(l, -1)) {
512 				const char *const name = LuaToString(l, -1);
513 				this->Index = UnitTypeVar.VariableNameLookup[name];
514 				if (this->Index == -1) {
515 					LuaError(l, "unknown variable '%s'" _C_ name);
516 				}
517 			} else {
518 				if (!lua_istable(l, -1)) {
519 					LuaError(l, "incorrect argument, need list of size 2 with {function, max} or a string with the name of a unit variable");
520 				}
521 				for (lua_pushnil(l); lua_next(l, -2); lua_pop(l, 1)) {
522 					const char *key = LuaToString(l, -2);
523 					if (!strcmp(key, "Max")) {
524 						this->ValueMax = LuaToNumber(l, -1);
525 					} else if (!strcmp(key, "Value")) {
526 						this->ValueFunc = CclParseNumberDesc(l);
527 						lua_pushnil(l); // ParseStringDesc eat token
528 					} else {
529 						lua_pop(l, 1);
530 						LuaError(l, "unknow value '%s'" _C_ key);
531 					}
532 				}
533 				if (this->ValueMax == -1) {
534 					this->ValueMax = 100;
535 				}
536 				if (this->ValueFunc == NULL) {
537 					LuaError(l, "didn't set a value function");
538 				}
539 			}
540 		} else if (!strcmp(key, "Height")) {
541 			this->Height = LuaToNumber(l, -1);
542 		} else if (!strcmp(key, "Width")) {
543 			this->Width = LuaToNumber(l, -1);
544 		} else if (!strcmp(key, "Colors")) {
545 			if (!lua_istable(l, -1)) {
546 				LuaError(l, "incorrect argument, need list");
547 			}
548 		    const int color_len = lua_rawlen(l, -1);
549 			if (color_len == 0) {
550 				LuaError(l, "need at least one {percentage, color} pair, got 0");
551 			}
552 			this->colors = new unsigned int[color_len];
553 			this->values = new unsigned int[color_len];
554 			int i = 0;
555 			for (lua_pushnil(l); lua_next(l, -2); lua_pop(l, 1)) {
556 				if (!lua_istable(l, -1) || lua_rawlen(l, -1) != 2) {
557 					LuaError(l, "incorrect argument, need list of size 2 with {percentage, color}");
558 				}
559 				this->values[i] = LuaToNumber(l, -1, 1);
560 				const char *const colorName = LuaToString(l, -1, 2);
561 				this->colors[i] = GetColorIndexByName(colorName);
562 				if (this->colors[i] == -1) {
563 					LuaError(l, "incorrect color: '%s' " _C_ colorName);
564 				}
565 				i++;
566 			}
567 			if (this->values[color_len - 1] != 0) {
568 				LuaError(l, "the last {percentage, color} pair must be for 0%%");
569 			}
570 		} else if (!strcmp(key, "Border")) {
571 			if (lua_isboolean(l, -1)) {
572 				if (LuaToBoolean(l, -1)) {
573 					this->hasBorder = 1;
574 				} else {
575 					this->hasBorder = 0;
576 				}
577 			} else {
578 				this->hasBorder = LuaToUnsignedNumber(l, -1);
579 				if (this->hasBorder == 0) {
580 					this->hasBorder = 1; // complete black is set to 1
581 				}
582 			}
583 		} else {
584 			LuaError(l, "'%s' invalid for method 'LifeBar' in DefinePanelContents" _C_ key);
585 		}
586 	}
587 	// Default value and checking errors.
588 	if (this->Height <= 0) {
589 		this->Height = 5; // Default value.
590 	}
591 	if (this->Width <= 0) {
592 		this->Width = 50; // Default value.
593 	}
594 	if (this->Index == -1 && this->ValueFunc == NULL) {
595 		LuaError(l, "variable undefined for LifeBar");
596 	}
597 	if (this->colors == NULL || this->values == NULL) {
598 		this->colors = new unsigned int[4];
599 		this->values = new unsigned int[4];
600 
601 		this->values[0] = 75;
602 		this->values[1] = 50;
603 		this->values[2] = 25;
604 		this->values[3] = 0;
605 
606 		this->colors[0] = GetColorIndexByName("dark-green");
607 		this->colors[1] = GetColorIndexByName("yellow");
608 		this->colors[2] = GetColorIndexByName("orange");;
609 		this->colors[3] = GetColorIndexByName("red");
610 	}
611 }
612 
Parse(lua_State * l)613 /* virtual */ void CContentTypeCompleteBar::Parse(lua_State *l)
614 {
615 	for (lua_pushnil(l); lua_next(l, -2); lua_pop(l, 1)) {
616 		const char *key = LuaToString(l, -2);
617 
618 		if (!strcmp(key, "Variable")) {
619 			const char *const name = LuaToString(l, -1);
620 			this->varIndex = UnitTypeVar.VariableNameLookup[name];
621 			if (this->varIndex == -1) {
622 				LuaError(l, "unknown variable '%s'" _C_ name);
623 			}
624 		} else if (!strcmp(key, "Height")) {
625 			this->height = LuaToNumber(l, -1);
626 		} else if (!strcmp(key, "Width")) {
627 			this->width = LuaToNumber(l, -1);
628 		} else if (!strcmp(key, "Border")) {
629 			this->hasBorder = LuaToBoolean(l, -1);
630 		} else if (!strcmp(key, "Color")) {
631 			const char *const colorName = LuaToString(l, -1);
632 			this->colorIndex = GetColorIndexByName(colorName);
633 			if (colorIndex == -1) {
634 				LuaError(l, "incorrect color: '%s' " _C_ colorName);
635 			}
636 		} else {
637 			LuaError(l, "'%s' invalid for method 'CompleteBar' in DefinePanelContents" _C_ key);
638 		}
639 	}
640 	// Default value and checking errors.
641 	if (this->height <= 0) {
642 		this->height = 5; // Default value.
643 	}
644 	if (this->width <= 0) {
645 		this->width = 50; // Default value.
646 	}
647 	if (this->varIndex == -1) {
648 		LuaError(l, "variable undefined for CompleteBar");
649 	}
650 }
651 
652 //@}
653