/spell/script_spell.cpp
DefineSpell


Parse Spell.

@param l Lua state.

/spell/script_spell.cpp:431 CclDefineSpell

static int CclDefineSpell(lua_State *l)
{
	const int args = lua_gettop(l);
	const std::string identname = LuaToString(l, 1);
	SpellType *spell = SpellTypeByIdent(identname);
	if (spell != NULL) {
		DebugPrint("Redefining spell-type '%s'\n" _C_ identname.c_str());
	} else {
		spell = new SpellType(SpellTypeTable.size(), identname);
		for (std::vector<CUnitType *>::size_type i = 0; i < UnitTypes.size(); ++i) { // adjust array for caster already defined
			if (UnitTypes[i]->CanCastSpell) {
				char *newc = new char[(SpellTypeTable.size() + 1) * sizeof(char)];
				memcpy(newc, UnitTypes[i]->CanCastSpell, SpellTypeTable.size() * sizeof(char));
				delete[] UnitTypes[i]->CanCastSpell;
				UnitTypes[i]->CanCastSpell = newc;
				UnitTypes[i]->CanCastSpell[SpellTypeTable.size()] = 0;
			}
			if (UnitTypes[i]->AutoCastActive) {
				char *newc = new char[(SpellTypeTable.size() + 1) * sizeof(char)];
				memcpy(newc, UnitTypes[i]->AutoCastActive, SpellTypeTable.size() * sizeof(char));
				delete[] UnitTypes[i]->AutoCastActive;
				UnitTypes[i]->AutoCastActive = newc;
				UnitTypes[i]->AutoCastActive[SpellTypeTable.size()] = 0;
			}
		}
		SpellTypeTable.push_back(spell);
	}
	for (int i = 1; i < args; ++i) {
		const char *value = LuaToString(l, i + 1);
		++i;
		if (!strcmp(value, "showname")) {
			spell->Name = LuaToString(l, i + 1);
		} else if (!strcmp(value, "manacost")) {
			spell->ManaCost = LuaToNumber(l, i + 1);
		} else if (!strcmp(value, "cooldown")) {
			spell->CoolDown = LuaToNumber(l, i + 1);
		} else if (!strcmp(value, "res-cost")) {
			lua_pushvalue(l, i + 1);
			if (!lua_istable(l, -1)) {
				LuaError(l, "incorrect argument");
			}
			const int len = lua_rawlen(l, -1);
			if (len != MaxCosts) {
				LuaError(l, "resource table size isn't correct");
			}
			for (int j = 1; j < len; ++j) { // exclude the time
				spell->Costs[j] = LuaToNumber(l, -1, j + 1);
			}
			lua_pop(l, 1);
		} else if (!strcmp(value, "range")) {
			if (!lua_isstring(l, i + 1) && !lua_isnumber(l, i + 1)) {
				LuaError(l, "incorrect argument");
			}
			if (lua_isstring(l, i + 1) && !strcmp(lua_tostring(l, i + 1), "infinite")) {
				spell->Range = INFINITE_RANGE;
			} else if (lua_isnumber(l, i + 1)) {
				spell->Range = static_cast<int>(lua_tonumber(l, i + 1));
			} else {
				LuaError(l, "Invalid range");
			}
		} else if (!strcmp(value, "repeat-cast")) {
			spell->RepeatCast = 1;
			--i;
		} else if (!strcmp(value, "force-use-animation")) {
			spell->ForceUseAnimation = true;
			--i;
		} else if (!strcmp(value, "target")) {
			value = LuaToString(l, i + 1);
			if (!strcmp(value, "self")) {
				spell->Target = TargetSelf;
			} else if (!strcmp(value, "unit")) {
				spell->Target = TargetUnit;
			} else if (!strcmp(value, "position")) {
				spell->Target = TargetPosition;
			} else {
				LuaError(l, "Unsupported spell target type tag: %s" _C_ value);
			}
		} else if (!strcmp(value, "action")) {
			if (!lua_istable(l, i + 1)) {
				LuaError(l, "incorrect argument");
			}
			const int subargs = lua_rawlen(l, i + 1);
			for (int k = 0; k < subargs; ++k) {
				lua_rawgeti(l, i + 1, k + 1);
				spell->Action.push_back(CclSpellAction(l));
				lua_pop(l, 1);
			}
		} else if (!strcmp(value, "condition")) {
			if (!spell->Condition) {
				spell->Condition = new ConditionInfo;
			}
			lua_pushvalue(l, i + 1);
			CclSpellCondition(l, spell->Condition);
			lua_pop(l, 1);
		} else if (!strcmp(value, "autocast")) {
			if (!spell->AutoCast) {
				spell->AutoCast = new AutoCastInfo();
			}
			lua_pushvalue(l, i + 1);
			CclSpellAutocast(l, spell->AutoCast);
			lua_pop(l, 1);
		} else if (!strcmp(value, "ai-cast")) {
			if (!spell->AICast) {
				spell->AICast = new AutoCastInfo();
			}
			lua_pushvalue(l, i + 1);
			CclSpellAutocast(l, spell->AICast);
			lua_pop(l, 1);
		} else if (!strcmp(value, "sound-when-cast")) {
			//  Free the old name, get the new one
			spell->SoundWhenCast.Name = LuaToString(l, i + 1);
			spell->SoundWhenCast.MapSound();
			//  Check for sound.
			if (!spell->SoundWhenCast.Sound) {
				spell->SoundWhenCast.Name.clear();
			}
		} else if (!strcmp(value, "depend-upgrade")) {
			value = LuaToString(l, i + 1);
			spell->DependencyId = UpgradeIdByIdent(value);
			if (spell->DependencyId == -1) {
				lua_pushfstring(l, "Bad upgrade name: %s", value);
			}
		} else {
			LuaError(l, "Unsupported tag: %s" _C_ value);
		}
	}
	return 0;
}


/ui/script_ui.cpp
AddMessage


Description

Add a new message.

Example:

AddMessage("Hello World!")


@param l Lua state.

/ui/script_ui.cpp:1267 CclAddMessage

static int CclAddMessage(lua_State *l)
{
	LuaCheckArgs(l, 1);
	SetMessage("%s", LuaToString(l, 1));
	return 0;
}

SetKeyScrollSpeed


Description

Set speed of key scroll

@param l Lua state.

Example:

SetKeyScrollSpeed(4)

/ui/script_ui.cpp:87 CclSetKeyScrollSpeed

static int CclSetKeyScrollSpeed(lua_State *l)
{
	LuaCheckArgs(l, 1);
	UI.KeyScrollSpeed = LuaToNumber(l, 1);
	return 0;
}

GetKeyScrollSpeed


Description

Get speed of key scroll

@param l Lua state.

Example:

scroll_speed = GetKeyScrollSpeed()
print(scroll_speed)

/ui/script_ui.cpp:106 CclGetKeyScrollSpeed

static int CclGetKeyScrollSpeed(lua_State *l)
{
	LuaCheckArgs(l, 0);
	lua_pushnumber(l, UI.KeyScrollSpeed);
	return 1;
}

SetMouseScrollSpeed


Description

Set speed of mouse scroll

@param l Lua state.

Example:

SetMouseScrollSpeed(2)

/ui/script_ui.cpp:124 CclSetMouseScrollSpeed

static int CclSetMouseScrollSpeed(lua_State *l)
{
	LuaCheckArgs(l, 1);
	UI.MouseScrollSpeed = LuaToNumber(l, 1);
	return 0;
}

GetMouseScrollSpeed


Description

Get speed of mouse scroll

@param l Lua state.

Example:

scroll_speed = GetMouseScrollSpeed()
print(scroll_speed)

/ui/script_ui.cpp:143 CclGetMouseScrollSpeed

static int CclGetMouseScrollSpeed(lua_State *l)
{
	LuaCheckArgs(l, 0);
	lua_pushnumber(l, UI.MouseScrollSpeed);
	return 1;
}

SetMouseScrollSpeedDefault


Set speed of middle-mouse scroll

@param l Lua state.

/ui/script_ui.cpp:155 CclSetMouseScrollSpeedDefault

static int CclSetMouseScrollSpeedDefault(lua_State *l)
{
	LuaCheckArgs(l, 1);
	UI.MouseScrollSpeedDefault = LuaToNumber(l, 1);
	return 0;
}

GetMouseScrollSpeedDefault


Get speed of middle-mouse scroll

@param l Lua state.

/ui/script_ui.cpp:167 CclGetMouseScrollSpeedDefault

static int CclGetMouseScrollSpeedDefault(lua_State *l)
{
	LuaCheckArgs(l, 0);
	lua_pushnumber(l, UI.MouseScrollSpeedDefault);
	return 0;
}

SetMouseScrollSpeedControl


Set speed of ctrl-middle-mouse scroll

@param l Lua state.

/ui/script_ui.cpp:179 CclSetMouseScrollSpeedControl

static int CclSetMouseScrollSpeedControl(lua_State *l)
{
	LuaCheckArgs(l, 1);
	UI.MouseScrollSpeedControl = LuaToNumber(l, 1);
	return 0;
}

GetMouseScrollSpeedControl


Get speed of ctrl-middle-mouse scroll

@param l Lua state.

/ui/script_ui.cpp:191 CclGetMouseScrollSpeedControl

static int CclGetMouseScrollSpeedControl(lua_State *l)
{
	LuaCheckArgs(l, 0);
	lua_pushnumber(l, UI.MouseScrollSpeedControl);
	return 0;
}

SetClickMissile


Set which missile is used for right click

@param l Lua state.

/ui/script_ui.cpp:209 CclSetClickMissile

static int CclSetClickMissile(lua_State *l)
{
	const int args = lua_gettop(l);
	if (args > 1 || (args == 1 && (!lua_isnil(l, 1) && !lua_isstring(l, 1)))) {
		LuaError(l, "incorrect argument");
	}
	ClickMissile.clear();
	if (args == 1 && !lua_isnil(l, 1)) {
		ClickMissile = lua_tostring(l, 1);
	}
	return 0;
}

SetDamageMissile


Set which missile shows Damage

@param l Lua state.

/ui/script_ui.cpp:228 CclSetDamageMissile

static int CclSetDamageMissile(lua_State *l)
{
	const int args = lua_gettop(l);

	if (args > 1 || (args == 1 && (!lua_isnil(l, 1) && !lua_isstring(l, 1)))) {
		LuaError(l, "incorrect argument");
	}
	DamageMissile.clear();
	if (args == 1 && !lua_isnil(l, 1)) {
		DamageMissile = lua_tostring(l, 1);
	}
	return 0;
}

SetVideoResolution


Description

Set the video resolution.

@param l Lua state.

Example:

SetVideoResolution(640,480)

/ui/script_ui.cpp:252 CclSetVideoResolution

static int CclSetVideoResolution(lua_State *l)
{
	LuaCheckArgs(l, 2);
	if (CclInConfigFile) {
		// May have been set from the command line
		if (!Video.Width || !Video.Height) {
			Video.Width = LuaToNumber(l, 1);
			Video.Height = LuaToNumber(l, 2);
		}
	}
	return 0;
}

GetVideoResolution


Description

Get the video resolution.

@param l Lua state.

Example:

width,height = GetVideoResolution()
print("Resolution is " .. width .. "x" .. height)

/ui/script_ui.cpp:272 CclGetVideoResolution

static int CclGetVideoResolution(lua_State *l)
{
	LuaCheckArgs(l, 0);
	lua_pushnumber(l, Video.Width);
	lua_pushnumber(l, Video.Height);
	return 2;
}

SetVideoFullScreen


Description

Set the video fullscreen mode.

@param l Lua state.

Example:

-- Full Screen mode enabled
SetVideoFullScreen(true)
-- Full Screen mode disabled
SetVideoFullScreen(false)

/ui/script_ui.cpp:298 CclSetVideoFullScreen

static int CclSetVideoFullScreen(lua_State *l)
{
	LuaCheckArgs(l, 1);
	if (CclInConfigFile) {
		// May have been set from the command line
		if (!VideoForceFullScreen) {
			Video.FullScreen = LuaToBoolean(l, 1);
		}
	}
	return 0;
}

GetVideoFullScreen


Description

Get the video fullscreen mode.

@param l Lua state.

Example:

fullscreenmode = GetVideoFullScreen()
print(fullscreenmode)

/ui/script_ui.cpp:317 CclGetVideoFullScreen

static int CclGetVideoFullScreen(lua_State *l)
{
	LuaCheckArgs(l, 0);
	lua_pushboolean(l, Video.FullScreen);
	return 1;
}

SetWindowSize


Request a specific initial window size

/ui/script_ui.cpp:333 CclSetWindowSize

static int CclSetWindowSize(lua_State *l)
{
	LuaCheckArgs(l, 2);
	if (CclInConfigFile) {
		// May have been set from the command line
		if (!Video.WindowWidth || !Video.WindowHeight) {
			Video.WindowWidth = LuaToNumber(l, 1);
			Video.WindowHeight = LuaToNumber(l, 2);
		}
	}
	return 0;
}

SetVerticalPixelSize


For games with non-square pixels, this sets the scale of vertical pixels versus horizontal pixels.
e.g., if your assets are 320x200, but you render at 320x240, this is 1.2.

/ui/script_ui.cpp:347 CclSetVerticalPixelSize

static int CclSetVerticalPixelSize(lua_State *l)
{
	LuaCheckArgs(l, 1);
	if (CclInConfigFile) {
		luaL_checktype(l, 1, LUA_TNUMBER);
		Video.VerticalPixelSize = static_cast<double>(lua_tonumber(l, 1));
	}
	return 0;
}

SetFontCodePage


Description

Declare which codepage the font files are in. Text is handled internally
as UTF-8 everywhere, but the font rendering system uses graphics with 256
symbols. Commonly, DOS and early Windows games used codepage 437 or 1252 for
western European languages, or 866 for Russian and some other cyrillic
writing systems. These are the only ones that are currently supported, but
more can easily be added. All text is mapped into the codepage that is set
for the font files. If the codepage is not one of the supported ones, or if
something doesn't map (for example, some accented characters with codepage
866, or cyrillic letters with codepage 437), a simple "visual" mapping to
7-bit ASCII is used to at least print something that may be recognizable.

/ui/script_ui.cpp:1344 CclSetFontCodePage

static int CclSetFontCodePage(lua_State *l)
{
	LuaCheckArgs(l, 1);
	FontCodePage = LuaToNumber(l, 1);

	return 0;
}

SetTitleScreens


Default title screens.

@param l Lua state.

/ui/script_ui.cpp:444 CclSetTitleScreens

static int CclSetTitleScreens(lua_State *l)
{
	if (TitleScreens) {
		for (int i = 0; TitleScreens[i]; ++i) {
			delete TitleScreens[i];
		}
		delete[] TitleScreens;
		TitleScreens = NULL;
	}

	const int args = lua_gettop(l);
	TitleScreens = new TitleScreen *[args + 1];
	memset(TitleScreens, 0, (args + 1) * sizeof(TitleScreen *));

	for (int j = 0; j < args; ++j) {
		if (!lua_istable(l, j + 1)) {
			LuaError(l, "incorrect argument");
		}
		TitleScreens[j] = new TitleScreen;
		TitleScreens[j]->Iterations = 1;
		lua_pushnil(l);
		while (lua_next(l, j + 1)) {
			const char *value = LuaToString(l, -2);
			if (!strcmp(value, "Image")) {
				TitleScreens[j]->File = LuaToString(l, -1);
			} else if (!strcmp(value, "Music")) {
				TitleScreens[j]->Music = LuaToString(l, -1);
			} else if (!strcmp(value, "Timeout")) {
				TitleScreens[j]->Timeout = LuaToNumber(l, -1);
			} else if (!strcmp(value, "Iterations")) {
				TitleScreens[j]->Iterations = LuaToNumber(l, -1);
			} else if (!strcmp(value, "Editor")) {
				TitleScreens[j]->Editor = LuaToNumber(l, -1);
			} else if (!strcmp(value, "Labels")) {
				if (!lua_istable(l, -1)) {
					LuaError(l, "incorrect argument");
				}
				const int subargs = lua_rawlen(l, -1);
				TitleScreens[j]->Labels = new TitleScreenLabel *[subargs + 1];
				memset(TitleScreens[j]->Labels, 0, (subargs + 1) * sizeof(TitleScreenLabel *));
				for (int k = 0; k < subargs; ++k) {
					lua_rawgeti(l, -1, k + 1);
					if (!lua_istable(l, -1)) {
						LuaError(l, "incorrect argument");
					}
					TitleScreens[j]->Labels[k] = new TitleScreenLabel;
					lua_pushnil(l);
					while (lua_next(l, -2)) {
						const char *value = LuaToString(l, -2);
						if (!strcmp(value, "Text")) {
							TitleScreens[j]->Labels[k]->Text = LuaToString(l, -1);
						} else if (!strcmp(value, "Font")) {
							TitleScreens[j]->Labels[k]->Font = CFont::Get(LuaToString(l, -1));
						} else if (!strcmp(value, "Pos")) {
							CclGetPos(l, &TitleScreens[j]->Labels[k]->Xofs, &TitleScreens[j]->Labels[k]->Yofs);
						} else if (!strcmp(value, "Flags")) {
							if (!lua_istable(l, -1)) {
								LuaError(l, "incorrect argument");
							}
							const int subsubargs = lua_rawlen(l, -1);
							for (int subk = 0; subk < subsubargs; ++subk) {
								const char *value = LuaToString(l, -1, subk + 1);
								if (!strcmp(value, "center")) {
									TitleScreens[j]->Labels[k]->Flags |= TitleFlagCenter;
								} else {
									LuaError(l, "incorrect flag");
								}
							}
						} else {
							LuaError(l, "Unsupported key: %s" _C_ value);
						}
						lua_pop(l, 1);
					}
					lua_pop(l, 1);
				}
			} else {
				LuaError(l, "Unsupported key: %s" _C_ value);
			}
			lua_pop(l, 1);
		}
	}
	return 0;
}

ShowTitleScreens

/ui/script_ui.cpp:355 CclShowTitleScreens

static int CclShowTitleScreens(lua_State *l)
{
	LuaCheckArgs(l, 0);
	ShowTitleScreens();
	lua_pushboolean(l, 1);
	return 1;
}

DefinePanelContents


Define the Panels.
Define what is shown in the panel(text, icon, variables)

@param l Lua state.
@return 0.

/ui/script_ui.cpp:630 CclDefinePanelContents

static int CclDefinePanelContents(lua_State *l)
{
	const int nargs = lua_gettop(l);

	for (int i = 0; i < nargs; i++) {
		Assert(lua_istable(l, i + 1));
		CUnitInfoPanel *infopanel = new CUnitInfoPanel;

		for (lua_pushnil(l); lua_next(l, i + 1); lua_pop(l, 1)) {
			const char *key = LuaToString(l, -2);

			if (!strcmp(key, "Ident")) {
				infopanel->Name = LuaToString(l, -1);
			} else if (!strcmp(key, "Pos")) {
				CclGetPos(l, &infopanel->PosX, &infopanel->PosY);
			} else if (!strcmp(key, "DefaultFont")) {
				infopanel->DefaultFont = CFont::Get(LuaToString(l, -1));
			} else if (!strcmp(key, "Condition")) {
				infopanel->Condition = ParseConditionPanel(l);
			} else if (!strcmp(key, "Contents")) {
				Assert(lua_istable(l, -1));
				for (size_t j = 0; j < lua_rawlen(l, -1); j++, lua_pop(l, 1)) {
					lua_rawgeti(l, -1, j + 1);
					infopanel->Contents.push_back(CclParseContent(l));
				}
			} else {
				LuaError(l, "'%s' invalid for DefinePanelContents" _C_ key);
			}
		}
		for (std::vector<CContentType *>::iterator content = infopanel->Contents.begin();
			 content != infopanel->Contents.end(); ++content) { // Default value for invalid value.
			(*content)->Pos.x += infopanel->PosX;
			(*content)->Pos.y += infopanel->PosY;
		}
		size_t j;
		for (j = 0; j < UI.InfoPanelContents.size(); ++j) {
			if (infopanel->Name == UI.InfoPanelContents[j]->Name) {
				DebugPrint("Redefinition of Panel '%s'\n" _C_ infopanel->Name.c_str());
				delete UI.InfoPanelContents[j];
				UI.InfoPanelContents[j] = infopanel;
				break;
			}
		}
		if (j == UI.InfoPanelContents.size()) {
			UI.InfoPanelContents.push_back(infopanel);
		}
	}
	return 0;
}

DefinePopup


Define the Panels.
Define what is shown in the panel(text, icon, variables)

@param l Lua state.
@return 0.

/ui/script_ui.cpp:682 CclDefinePopup

static int CclDefinePopup(lua_State *l)
{
	Assert(lua_istable(l, 1));

	CPopup *popup = new CPopup;

	for (lua_pushnil(l); lua_next(l, 1); lua_pop(l, 1)) {
		const char *key = LuaToString(l, -2);

		if (!strcmp(key, "Ident")) {
			popup->Ident = LuaToString(l, -1);
		} else if (!strcmp(key, "DefaultFont")) {
			popup->DefaultFont = CFont::Get(LuaToString(l, -1));
		} else if (!strcmp(key, "BackgroundColor")) {
			popup->BackgroundColor = LuaToUnsignedNumber(l, -1);
		} else if (!strcmp(key, "BorderColor")) {
			popup->BorderColor = LuaToUnsignedNumber(l, -1);
		} else if (!strcmp(key, "Margin")) {
			CclGetPos(l, &popup->MarginX, &popup->MarginY);
		} else if (!strcmp(key, "MinWidth")) {
			popup->MinWidth = LuaToNumber(l, -1);
		} else if (!strcmp(key, "MinHeight")) {
			popup->MinHeight = LuaToNumber(l, -1);
		} else if (!strcmp(key, "Contents")) {
			Assert(lua_istable(l, -1));
			for (size_t j = 0; j < lua_rawlen(l, -1); j++, lua_pop(l, 1)) {
				lua_rawgeti(l, -1, j + 1);
				popup->Contents.push_back(CPopupContentType::ParsePopupContent(l));
			}
		} else {
			LuaError(l, "'%s' invalid for DefinePopups" _C_ key);
		}
	}
	for (size_t j = 0; j < UI.ButtonPopups.size(); ++j) {
		if (popup->Ident == UI.ButtonPopups[j]->Ident) {
			DebugPrint("Redefinition of Popup '%s'\n" _C_ popup->Ident.c_str());
			delete UI.ButtonPopups[j];
			UI.ButtonPopups[j] = popup;
			return 0;
		}
	}
	UI.ButtonPopups.push_back(popup);
	return 0;
}

DefineViewports


Define the viewports.

@param l Lua state.

/ui/script_ui.cpp:716 CclDefineViewports

static int CclDefineViewports(lua_State *l)
{
	int i = 0;
	const int args = lua_gettop(l);

	for (int j = 0; j < args; ++j) {
		const char *value = LuaToString(l, j + 1);
		++j;
		if (!strcmp(value, "mode")) {
			UI.ViewportMode = (ViewportModeType)LuaToNumber(l, j + 1);
		} else if (!strcmp(value, "viewport")) {
			if (!lua_istable(l, j + 1) && lua_rawlen(l, j + 1) != 3) {
				LuaError(l, "incorrect argument");
			}
			UI.Viewports[i].MapPos.x = LuaToNumber(l, j + 1, 1);
			UI.Viewports[i].MapPos.y = LuaToNumber(l, j + 1, 2);
			const int slot = LuaToNumber(l, j + 1, 3);
			if (slot != -1) {
				UI.Viewports[i].Unit = &UnitManager->GetSlotUnit(slot);
			}
			++i;
		} else {
			LuaError(l, "Unsupported tag: %s" _C_ value);
		}
	}
	UI.NumViewports = i;
	return 0;
}

RightButtonAttacks


Fighter right button attacks as default.

@param l Lua state.

/ui/script_ui.cpp:728 CclRightButtonAttacks

static int CclRightButtonAttacks(lua_State *l)
{
	LuaCheckArgs(l, 0);
	RightButtonAttacks = true;
	return 0;
}

RightButtonMoves


Fighter right button moves as default.

@param l Lua state.

/ui/script_ui.cpp:740 CclRightButtonMoves

static int CclRightButtonMoves(lua_State *l)
{
	LuaCheckArgs(l, 0);
	RightButtonAttacks = false;
	return 0;
}

SetFancyBuildings


Description

Enable/disable the fancy buildings.

@param l Lua state.

Example:

-- Enable fancy buildings
SetFancyBuildings(true)
-- Disable fancy buildings
SetFancyBuildings(false)

/ui/script_ui.cpp:761 CclSetFancyBuildings

static int CclSetFancyBuildings(lua_State *l)
{
	LuaCheckArgs(l, 1);
	FancyBuildings = LuaToBoolean(l, 1);
	return 0;
}

DefineButton


Define a button.

@param l Lua state.

/ui/script_ui.cpp:1160 CclDefineButton

static int CclDefineButton(lua_State *l)
{
	LuaCheckArgs(l, 1);
	if (!lua_istable(l, 1)) {
		LuaError(l, "incorrect argument");
	}
	ButtonAction ba;

	//
	// Parse the arguments
	//
	lua_pushnil(l);
	while (lua_next(l, 1)) {
		const char *value = LuaToString(l, -2);
		if (!strcmp(value, "Pos")) {
			ba.Pos = LuaToNumber(l, -1);
		} else if (!strcmp(value, "Level")) {
			ba.Level = LuaToNumber(l, -1);
		} else if (!strcmp(value, "AlwaysShow")) {
			ba.AlwaysShow = LuaToBoolean(l, -1);
		} else if (!strcmp(value, "Icon")) {
			ba.Icon.Name = LuaToString(l, -1);
		} else if (!strcmp(value, "Action")) {
			value = LuaToString(l, -1);
			if (!strcmp(value, "move")) {
				ba.Action = ButtonMove;
			} else if (!strcmp(value, "stop")) {
				ba.Action = ButtonStop;
			} else if (!strcmp(value, "attack")) {
				ba.Action = ButtonAttack;
			} else if (!strcmp(value, "repair")) {
				ba.Action = ButtonRepair;
			} else if (!strcmp(value, "harvest")) {
				ba.Action = ButtonHarvest;
			} else if (!strcmp(value, "button")) {
				ba.Action = ButtonButton;
			} else if (!strcmp(value, "build")) {
				ba.Action = ButtonBuild;
			} else if (!strcmp(value, "train-unit")) {
				ba.Action = ButtonTrain;
			} else if (!strcmp(value, "patrol")) {
				ba.Action = ButtonPatrol;
			} else if (!strcmp(value, "explore")) {
				ba.Action = ButtonExplore;
			} else if (!strcmp(value, "stand-ground")) {
				ba.Action = ButtonStandGround;
			} else if (!strcmp(value, "attack-ground")) {
				ba.Action = ButtonAttackGround;
			} else if (!strcmp(value, "return-goods")) {
				ba.Action = ButtonReturn;
			} else if (!strcmp(value, "cast-spell")) {
				ba.Action = ButtonSpellCast;
			} else if (!strcmp(value, "research")) {
				ba.Action = ButtonResearch;
			} else if (!strcmp(value, "upgrade-to")) {
				ba.Action = ButtonUpgradeTo;
			} else if (!strcmp(value, "unload")) {
				ba.Action = ButtonUnload;
			} else if (!strcmp(value, "cancel")) {
				ba.Action = ButtonCancel;
			} else if (!strcmp(value, "cancel-upgrade")) {
				ba.Action = ButtonCancelUpgrade;
			} else if (!strcmp(value, "cancel-train-unit")) {
				ba.Action = ButtonCancelTrain;
			} else if (!strcmp(value, "cancel-build")) {
				ba.Action = ButtonCancelBuild;
			} else if (!strcmp(value, "callback")) {
				ba.Action = ButtonCallbackAction;
			} else {
				LuaError(l, "Unsupported button action: %s" _C_ value);
			}
		} else if (!strcmp(value, "Value")) {
			if (!lua_isnumber(l, -1) && !lua_isstring(l, -1) && !lua_isfunction(l, -1)) {
				LuaError(l, "incorrect argument");
			}

			if (lua_isfunction(l, -1)) {
				ba.Payload = new LuaCallback(l, -1);
			} else {
				char buf[64];
				const char *s2;

				if (lua_isnumber(l, -1)) {
					snprintf(buf, sizeof(buf), "%ld", (long int)lua_tonumber(l, -1));
					s2 = buf;
				} else {
					s2 = lua_tostring(l, -1);
				}
				ba.ValueStr = s2;
			}
		} else if (!strcmp(value, "Allowed")) {
			value = LuaToString(l, -1);
			if (!strcmp(value, "check-true")) {
				ba.Allowed = ButtonCheckTrue;
			} else if (!strcmp(value, "check-false")) {
				ba.Allowed = ButtonCheckFalse;
			} else if (!strcmp(value, "check-upgrade")) {
				ba.Allowed = ButtonCheckUpgrade;
			} else if (!strcmp(value, "check-individual-upgrade")) {
				ba.Allowed = ButtonCheckIndividualUpgrade;
			} else if (!strcmp(value, "check-unit-variable")) {
				ba.Allowed = ButtonCheckUnitVariable;
			} else if (!strcmp(value, "check-units-or")) {
				ba.Allowed = ButtonCheckUnitsOr;
			} else if (!strcmp(value, "check-units-and")) {
				ba.Allowed = ButtonCheckUnitsAnd;
			} else if (!strcmp(value, "check-units-not")) {
				ba.Allowed = ButtonCheckUnitsNot;
			} else if (!strcmp(value, "check-units-nor")) {
				ba.Allowed = ButtonCheckUnitsNor;
			} else if (!strcmp(value, "check-network")) {
				ba.Allowed = ButtonCheckNetwork;
			} else if (!strcmp(value, "check-no-network")) {
				ba.Allowed = ButtonCheckNoNetwork;
			} else if (!strcmp(value, "check-no-work")) {
				ba.Allowed = ButtonCheckNoWork;
			} else if (!strcmp(value, "check-no-research")) {
				ba.Allowed = ButtonCheckNoResearch;
			} else if (!strcmp(value, "check-attack")) {
				ba.Allowed = ButtonCheckAttack;
			} else if (!strcmp(value, "check-upgrade-to")) {
				ba.Allowed = ButtonCheckUpgradeTo;
			} else if (!strcmp(value, "check-research")) {
				ba.Allowed = ButtonCheckResearch;
			} else if (!strcmp(value, "check-single-research")) {
				ba.Allowed = ButtonCheckSingleResearch;
			} else if (!strcmp(value, "check-debug")) {
				ba.Allowed = ButtonCheckDebug;
			} else {
				LuaError(l, "Unsupported action: %s" _C_ value);
			}
		} else if (!strcmp(value, "AllowArg")) {
			if (!lua_istable(l, -1)) {
				LuaError(l, "incorrect argument");
			}
			std::string allowstr;
			const unsigned int subargs = lua_rawlen(l, -1);

			for (unsigned int k = 0; k < subargs; ++k) {
				const char *s2 = LuaToString(l, -1, k + 1);
				allowstr += s2;
				if (k != subargs - 1) {
					allowstr += ",";
				}
			}
			ba.AllowStr = allowstr;
		} else if (!strcmp(value, "Key")) {
			std::string key(LuaToString(l, -1));
			ba.Key = GetHotKey(key);
		} else if (!strcmp(value, "Hint")) {
			ba.Hint = LuaToString(l, -1);
		} else if (!strcmp(value, "Description")) {
			ba.Description = LuaToString(l, -1);
		} else if (!strcmp(value, "CommentSound")) {
			ba.CommentSound.Name = LuaToString(l, -1);
		} else if (!strcmp(value, "ButtonCursor")) {
			ba.ButtonCursor = LuaToString(l, -1);
		} else if (!strcmp(value, "Popup")) {
			ba.Popup = LuaToString(l, -1);
		} else if (!strcmp(value, "ForUnit")) {
			if (!lua_istable(l, -1)) {
				LuaError(l, "incorrect argument");
			}
			// FIXME: ba.UnitMask shouldn't be a string
			std::string umask = ",";
			const unsigned subargs = lua_rawlen(l, -1);
			for (unsigned int k = 0; k < subargs; ++k) {
				const char *s2 = LuaToString(l, -1, k + 1);
				umask += s2;
				umask += ",";
			}
			ba.UnitMask = umask;
			if (!strncmp(ba.UnitMask.c_str(), ",*,", 3)) {
				ba.UnitMask = "*";
			}
		} else {
			LuaError(l, "Unsupported tag: %s" _C_ value);
		}
		lua_pop(l, 1);
	}
	AddButton(ba.Pos, ba.Level, ba.Icon.Name, ba.Action, ba.ValueStr, ba.Payload,
			  ba.Allowed, ba.AllowStr, ba.Key, ba.Hint, ba.Description, ba.CommentSound.Name,
			  ba.ButtonCursor, ba.UnitMask, ba.Popup, ba.AlwaysShow);
	return 0;
}

ClearButtons


Clear all buttons

@param l Lua state.

/ui/script_ui.cpp:969 CclClearButtons

static int CclClearButtons(lua_State *l)
{
	LuaCheckArgs(l, 0);
	CleanButtons();
	return 0;
}

CopyButtonsForUnitType

/ui/script_ui.cpp:1186 CclCopyButtonsForUnitType

static int CclCopyButtonsForUnitType(lua_State *l)
{
	LuaCheckArgs(l, 2);

	// Slot identifier
	const char* fromName = LuaToString(l, 1);
	CUnitType *from = UnitTypeByIdent(fromName);
	const char* toName = LuaToString(l, 2);
	CUnitType *to = UnitTypeByIdent(toName);
	if (!to) {
		LuaError(l, "Unknown unit-type '%s'\n" _C_ toName);
	}
	if (!from) {
		LuaError(l, "Unknown unit-type '%s'\n" _C_ fromName);
	}

	for (auto btn : UnitButtonTable) {
		if (btn->UnitMask.find(fromName) != std::string::npos) {
			btn->UnitMask += toName;
			btn->UnitMask += ",";
		}
	}

	return 0;
}

DefineButtonStyle


Define a button style

@param l Lua state.

/ui/script_ui.cpp:925 CclDefineButtonStyle

static int CclDefineButtonStyle(lua_State *l)
{
	LuaCheckArgs(l, 2);
	if (!lua_istable(l, 2)) {
		LuaError(l, "incorrect argument");
	}
	const char *style = LuaToString(l, 1);
	ButtonStyle *&b = ButtonStyleHash[style];
	if (!b) {
		b = new ButtonStyle;
		// Set to bogus value to see if it was set later
		b->Default.TextPos.x = b->Hover.TextPos.x = b->Clicked.TextPos.x = 0xFFFFFF;
	}

	lua_pushnil(l);
	while (lua_next(l, 2)) {
		const char *value = LuaToString(l, -2);

		if (!strcmp(value, "Size")) {
			CclGetPos(l, &b->Width, &b->Height);
		} else if (!strcmp(value, "Font")) {
			b->Font = CFont::Get(LuaToString(l, -1));
		} else if (!strcmp(value, "TextNormalColor")) {
			b->TextNormalColor = LuaToString(l, -1);
		} else if (!strcmp(value, "TextReverseColor")) {
			b->TextReverseColor = LuaToString(l, -1);
		} else if (!strcmp(value, "TextPos")) {
			CclGetPos(l, &b->TextX, &b->TextY);
		} else if (!strcmp(value, "TextAlign")) {
			value = LuaToString(l, -1);
			if (!strcmp(value, "Center")) {
				b->TextAlign = TextAlignCenter;
			} else if (!strcmp(value, "Right")) {
				b->TextAlign = TextAlignRight;
			} else if (!strcmp(value, "Left")) {
				b->TextAlign = TextAlignLeft;
			} else {
				LuaError(l, "Invalid text alignment: %s" _C_ value);
			}
		} else if (!strcmp(value, "Default")) {
			ParseButtonStyleProperties(l, &b->Default);
		} else if (!strcmp(value, "Hover")) {
			ParseButtonStyleProperties(l, &b->Hover);
		} else if (!strcmp(value, "Clicked")) {
			ParseButtonStyleProperties(l, &b->Clicked);
		} else {
			LuaError(l, "Unsupported tag: %s" _C_ value);
		}
		lua_pop(l, 1);
	}

	if (b->Default.TextPos.x == 0xFFFFFF) {
		b->Default.TextPos.x = b->TextX;
		b->Default.TextPos.y = b->TextY;
	}
	if (b->Hover.TextPos.x == 0xFFFFFF) {
		b->Hover.TextPos.x = b->TextX;
		b->Hover.TextPos.y = b->TextY;
	}
	if (b->Clicked.TextPos.x == 0xFFFFFF) {
		b->Clicked.TextPos.x = b->TextX;
		b->Clicked.TextPos.y = b->TextY;
	}

	if (b->Default.TextAlign == TextAlignUndefined) {
		b->Default.TextAlign = b->TextAlign;
	}
	if (b->Hover.TextAlign == TextAlignUndefined) {
		b->Hover.TextAlign = b->TextAlign;
	}
	if (b->Clicked.TextAlign == TextAlignUndefined) {
		b->Clicked.TextAlign = b->TextAlign;
	}
	return 0;
}

PresentMap


Description

Set basic map caracteristics.

@param l Lua state.

Example:

PresentMap("Map description", 1, 128, 128, 17)

/ui/script_ui.cpp:1303 CclPresentMap

static int CclPresentMap(lua_State *l)
{
	LuaCheckArgs(l, 5);

	Map.Info.Description = LuaToString(l, 1);
	// Number of players in LuaToNumber(l, 3); // Not used yet.
	Map.Info.MapWidth = LuaToNumber(l, 3);
	Map.Info.MapHeight = LuaToNumber(l, 4);
	Map.Info.MapUID = LuaToNumber(l, 5);

	return 0;
}

DefineMapSetup


Description

Define the lua file that will build the map

@param l Lua state.

Example:

-- Load map setup from file
DefineMapSetup("Setup.sms")

/ui/script_ui.cpp:1323 CclDefineMapSetup

static int CclDefineMapSetup(lua_State *l)
{
	LuaCheckArgs(l, 1);
	Map.Info.Filename = LuaToString(l, 1);

	return 0;
}

SetSelectionStyle


Set selection style.

@param l Lua state.

/ui/script_ui.cpp:1249 CclSetSelectionStyle

static int CclSetSelectionStyle(lua_State *l)
{
	if (lua_gettop(l) < 1) {
		LuaError(l, "incorrect argument");
	}

	const char *style = LuaToString(l, 1);
	if (!strcmp(style, "rectangle")) {
		LuaCheckArgs(l, 1);
		DrawSelection = DrawSelectionRectangle;
	} else if (!strcmp(style, "alpha-rectangle")) {
		LuaCheckArgs(l, 1);
		DrawSelection = DrawSelectionRectangleWithTrans;
	} else if (!strcmp(style, "circle")) {
		LuaCheckArgs(l, 1);
		DrawSelection = DrawSelectionCircle;
	} else if (!strcmp(style, "alpha-circle")) {
		LuaCheckArgs(l, 1);
		DrawSelection = DrawSelectionCircleWithTrans;
	} else if (!strcmp(style, "corners")) {
		LuaCheckArgs(l, 1);
		DrawSelection = DrawSelectionCorners;
	} else if (!strcmp(style, "ellipse")) {
		LuaCheckArgs(l, 2);
		float factor = LuaToFloat(l, 2);
		DrawSelection = DrawSelectionEllipse(factor);
	} else {
		LuaError(l, "Unsupported selection style");
	}
	return 0;
}

SetGroupKeys


Set the keys which are use for grouping units, helpful for other keyboards

@param l Lua state.

/ui/script_ui.cpp:1279 CclSetGroupKeys

static int CclSetGroupKeys(lua_State *l)
{
	LuaCheckArgs(l, 1);
	UiGroupKeys = LuaToString(l, 1);
	return 0;
}


/unit/depend.cpp
DefineDependency


Define a new dependency.

@param l Lua state.

/unit/depend.cpp:461 CclDefineDependency

static int CclDefineDependency(lua_State *l)
{
	const int args = lua_gettop(l);
	const char *target = LuaToString(l, 1);

	//  All or rules.
	int or_flag = 0;
	for (int j = 1; j < args; ++j) {
		if (!lua_istable(l, j + 1)) {
			LuaError(l, "incorrect argument");
		}
		const int subargs = lua_rawlen(l, j + 1);

		for (int k = 0; k < subargs; ++k) {
			const char *required = LuaToString(l, j + 1, k + 1);
			int count = 1;
			if (k + 1 < subargs) {
				lua_rawgeti(l, j + 1, k + 2);
				if (lua_isnumber(l, -1)) {
					count = LuaToNumber(l, -1);
					++k;
				}
				lua_pop(l, 1);
			}
			AddDependency(target, required, count, or_flag);
			or_flag = 0;
		}
		if (j + 1 < args) {
			++j;
			const char *value = LuaToString(l, j + 1);
			if (strcmp(value, "or")) {
				LuaError(l, "not or symbol: %s" _C_ value);
				return 0;
			}
			or_flag = 1;
		}
	}
	return 0;
}

GetDependency


Get the dependency.

@todo not written.

@param l Lua state.

/unit/depend.cpp:475 CclGetDependency

static int CclGetDependency(lua_State *l)
{
	DebugPrint("FIXME: write this %p\n" _C_(void *)l);

	return 0;
}

CheckDependency


Checks if dependencies are met.

@return true if the dependencies are met.

@param l Lua state.
Argument 1: player
Argument 2: object which we want to check the dependencies of

/unit/depend.cpp:499 CclCheckDependency

static int CclCheckDependency(lua_State *l)
{
	LuaCheckArgs(l, 2);
	const char *object = LuaToString(l, 2);
	lua_pop(l, 1);
	const int plynr = TriggerGetPlayer(l);
	if (plynr == -1) {
		LuaError(l, "bad player: %i" _C_ plynr);
	}
	CPlayer &player = Players[plynr];

	lua_pushboolean(l, CheckDependByIdent(player, object));
	return 1;
}


/unit/upgrade.cpp
DefineModifier


Define a new upgrade modifier.

@param l List of modifiers.

/unit/upgrade.cpp:360 CclDefineModifier

static int CclDefineModifier(lua_State *l)
{
	const int args = lua_gettop(l);

	CUpgradeModifier *um = new CUpgradeModifier;

	memset(um->ChangeUpgrades, '?', sizeof(um->ChangeUpgrades));
	memset(um->ApplyTo, '?', sizeof(um->ApplyTo));
	um->Modifier.Variables = new CVariable[UnitTypeVar.GetNumberVariable()];
	um->ModifyPercent = new int[UnitTypeVar.GetNumberVariable()];
	memset(um->ModifyPercent, 0, UnitTypeVar.GetNumberVariable() * sizeof(int));

	std::string upgrade_ident = LuaToString(l, 1);
	um->UpgradeId = UpgradeIdByIdent(upgrade_ident);
	if (um->UpgradeId == -1) {
		LuaError(l, "Error when defining upgrade modifier: upgrade \"%s\" doesn't exist." _C_ upgrade_ident.c_str());
	}

	for (int j = 1; j < args; ++j) {
		if (!lua_istable(l, j + 1)) {
			LuaError(l, "incorrect argument");
		}
		const char *key = LuaToString(l, j + 1, 1);
#if 0 // To be removed. must modify lua file.
		if (!strcmp(key, "attack-range")) {
			key = "AttackRange";
		} else if (!strcmp(key, "sight-range")) {
			key = "SightRange";
		} else if (!strcmp(key, "basic-damage")) {
			key = "BasicDamage";
		} else if (!strcmp(key, "piercing-damage")) {
			key = "PiercingDamage";
		} else if (!strcmp(key, "armor")) {
			key = "Armor";
		} else if (!strcmp(key, "hit-points")) {
			key = "HitPoints";
		}
#endif
		if (!strcmp(key, "regeneration-rate")) {
			um->Modifier.Variables[HP_INDEX].Increase = LuaToNumber(l, j + 1, 2);
		} else if (!strcmp(key, "regeneration-frequency")) {
			um->Modifier.Variables[HP_INDEX].IncreaseFrequency = LuaToNumber(l, j + 1, 2);
		} else if (!strcmp(key, "cost")) {
			if (!lua_istable(l, j + 1) || lua_rawlen(l, j + 1) != 2) {
				LuaError(l, "incorrect argument");
			}
			const char *value = LuaToString(l, j + 1, 1);
			const int resId = GetResourceIdByName(l, value);
			um->Modifier.Costs[resId] = LuaToNumber(l, j + 1, 2);
		} else if (!strcmp(key, "storing")) {
			if (!lua_istable(l, j + 1) || lua_rawlen(l, j + 1) != 2) {
				LuaError(l, "incorrect argument");
			}
			const char *value = LuaToString(l, j + 1, 1);
			const int resId = GetResourceIdByName(l, value);
			um->Modifier.Storing[resId] = LuaToNumber(l, j + 1, 2);
		} else if (!strcmp(key, "improve-production")) {
			const char *value = LuaToString(l, j + 1, 2);
			const int resId = GetResourceIdByName(l, value);
			um->Modifier.ImproveIncomes[resId] = LuaToNumber(l, j + 1, 3);
		} else if (!strcmp(key, "allow-unit")) {
			const char *value = LuaToString(l, j + 1, 2);

			if (!strncmp(value, "unit-", 5)) {
				um->ChangeUnits[UnitTypeIdByIdent(value)] = LuaToNumber(l, j + 1, 3);
			} else {
				LuaError(l, "unit expected");
			}
		} else if (!strcmp(key, "allow")) {
			const char *value = LuaToString(l, j + 1, 2);
			if (!strncmp(value, "upgrade-", 8)) {
				um->ChangeUpgrades[UpgradeIdByIdent(value)] = LuaToNumber(l, j + 1, 3);
			} else {
				LuaError(l, "upgrade expected");
			}
		} else if (!strcmp(key, "apply-to")) {
			const char *value = LuaToString(l, j + 1, 2);
			um->ApplyTo[UnitTypeIdByIdent(value)] = 'X';
		} else if (!strcmp(key, "convert-to")) {
			const char *value = LuaToString(l, j + 1, 2);
			um->ConvertTo = UnitTypeByIdent(value);
		} else if (!strcmp(key, "research-speed")) {
			um->SpeedResearch = LuaToNumber(l, j + 1, 2);
		} else {
			int index = UnitTypeVar.VariableNameLookup[key]; // variable index;
			if (index != -1) {
				if (lua_rawlen(l, j + 1) == 3) {
					const char *value = LuaToString(l, j + 1, 3);
					if (!strcmp(value, "Percent")) {
						um->ModifyPercent[index] = LuaToNumber(l, j + 1, 2);
					}
				} else {
					lua_rawgeti(l, j + 1, 2);
					if (lua_istable(l, -1)) {
						DefineVariableField(l, um->Modifier.Variables + index, -1);
					} else if (lua_isnumber(l, -1)) {
						um->Modifier.Variables[index].Enable = 1;
						um->Modifier.Variables[index].Value = LuaToNumber(l, -1);
						um->Modifier.Variables[index].Max = LuaToNumber(l, -1);
					} else {
						LuaError(l, "bad argument type for '%s'\n" _C_ key);
					}
					lua_pop(l, 1);
				}
			} else {
				LuaError(l, "wrong tag: %s" _C_ key);
			}
		}
	}

	UpgradeModifiers[NumUpgradeModifiers++] = um;

	return 0;
}

DefineAllow


Description

Define which units/upgrades are allowed.

Example:

DefineAllow("unit-town-hall","AAAAAAAAAAAAAAAA") -- Available for everybody
DefineAllow("unit-stables","FFFFFFFFFFFFFFFF") -- Not available
DefineAllow("upgrade-sword1","RRRRRRRRRRRRRRRR") -- Upgrade already researched.

/unit/upgrade.cpp:432 CclDefineAllow

static int CclDefineAllow(lua_State *l)
{
	const int UnitMax = 65536; /// How many units supported
	const int args = lua_gettop(l);

	for (int j = 0; j < args; ++j) {
		const char *ident = LuaToString(l, j + 1);
		++j;
		const char *ids = LuaToString(l, j + 1);

		int n = strlen(ids);
		if (n > PlayerMax) {
			fprintf(stderr, "%s: Allow string too long %d\n", ident, n);
			n = PlayerMax;
		}

		if (!strncmp(ident, "unit-", 5)) {
			int id = UnitTypeIdByIdent(ident);
			for (int i = 0; i < n; ++i) {
				if (ids[i] == 'A') {
					AllowUnitId(Players[i], id, UnitMax);
				} else if (ids[i] == 'F') {
					AllowUnitId(Players[i], id, 0);
				}
			}
		} else if (!strncmp(ident, "upgrade-", 8)) {
			int id = UpgradeIdByIdent(ident);
			for (int i = 0; i < n; ++i) {
				AllowUpgradeId(Players[i], id, ids[i]);
			}
		} else {
			DebugPrint(" wrong ident %s\n" _C_ ident);
		}
	}
	return 0;
}

DefineUnitAllow


Define which units are allowed and how much.

/unit/upgrade.cpp:383 CclDefineUnitAllow

static int CclDefineUnitAllow(lua_State *l)
{
	const int args = lua_gettop(l);

	const char *ident = LuaToString(l, 0 + 1);

	if (strncmp(ident, "unit-", 5)) {
		DebugPrint(" wrong ident %s\n" _C_ ident);
		return 0;
	}
	int id = UnitTypeIdByIdent(ident);

	int i = 0;
	for (int j = 1; j < args && i < PlayerMax; ++j) {
		AllowUnitId(Players[i], id, LuaToNumber(l, j + 1));
		++i;
	}
	return 0;
}


/unit/script_unit.cpp
SetTrainingQueue


Description

Set training queue

@param l Lua state.

@return The old state of the training queue

Example:

-- Training queue available. Train multiple units.
SetTrainingQueue(true)
-- Train one unit at a time.
SetTrainingQueue(false)

/unit/script_unit.cpp:88 CclSetTrainingQueue

static int CclSetTrainingQueue(lua_State *l)
{
	LuaCheckArgs(l, 1);
	EnableTrainingQueue = LuaToBoolean(l, 1);
	return 0;
}

SetBuildingCapture


Set capture buildings

@param l Lua state.

@return The old state of the flag

Example:

SetBuildingCapture(true)
SetBuildingCapture(false)

/unit/script_unit.cpp:107 CclSetBuildingCapture

static int CclSetBuildingCapture(lua_State *l)
{
	LuaCheckArgs(l, 1);
	EnableBuildingCapture = LuaToBoolean(l, 1);
	return 0;
}

SetRevealAttacker


Set reveal attacker

@param l Lua state.

@return The old state of the flag

Example:

SetRevealAttacker(true)
SetRevealAttacker(false)

/unit/script_unit.cpp:126 CclSetRevealAttacker

static int CclSetRevealAttacker(lua_State *l)
{
	LuaCheckArgs(l, 1);
	RevealAttacker = LuaToBoolean(l, 1);
	return 0;
}

ResourcesMultiBuildersMultiplier


Set cost multiplier to RepairCost for buildings additional workers helping (0 = no additional cost)

@param l Lua state.

Example:

-- No cost
ResourcesMultiBuildersMultiplier(0)
-- Each builder helping will cost 1 resource
ResourcesMultiBuildersMultiplier(1)
-- Each builder helping will cost 10 resource
ResourcesMultiBuildersMultiplier(10)

/unit/script_unit.cpp:147 CclResourcesMultiBuildersMultiplier

static int CclResourcesMultiBuildersMultiplier(lua_State *l)
{
	LuaCheckArgs(l, 1);
	ResourcesMultiBuildersMultiplier = LuaToNumber(l, 1);
	return 0;
}

Unit


Parse unit

@param l Lua state.

@todo Verify that vision table is always correct (transporter)
@todo (PlaceUnit() and host-info).

Example:

footman = CreateUnit("unit-footman", 0, {0, 1})
-- The unit will appear selected
Unit(footman,{"selected"})
-- The unit will be considered destroyed
Unit(footman,{"destroyed"})
-- The unit will be considered removed
Unit(footman,{"removed"})
-- The unit will be considered as a summoned unit
Unit(footman,{"summoned",500})
-- The unit will face on south
Unit(footman,{"direction",0})
-- The unit will be displayed with his 3rd frame
Unit(footman,{"frame", 3})
-- The footman will have a high sight
Unit(footman,{"current-sight-range",9})
-- Change the unit color to be the ones from player 1
Unit(footman,{"rescued-from",1})

/unit/script_unit.cpp:658 CclUnit

static int CclUnit(lua_State *l)
{
	const int slot = LuaToNumber(l, 1);

	if (!lua_istable(l, 2)) {
		LuaError(l, "incorrect argument");
	}

	CUnit *unit = &UnitManager->GetSlotUnit(slot);
	bool hadType = unit->Type != NULL;
	CUnitType *type = NULL;
	CUnitType *seentype = NULL;
	CPlayer *player = NULL;

	// Parse the list:
	const int args = lua_rawlen(l, 2);
	for (int j = 0; j < args; ++j) {
		const char *value = LuaToString(l, 2, j + 1);
		++j;

		if (!strcmp(value, "type")) {
			type = UnitTypeByIdent(LuaToString(l, 2, j + 1));
		} else if (!strcmp(value, "seen-type")) {
			seentype = UnitTypeByIdent(LuaToString(l, 2, j + 1));
		} else if (!strcmp(value, "player")) {
			player = &Players[LuaToNumber(l, 2, j + 1)];

			// During a unit's death animation (when action is "die" but the
			// unit still has its original type, i.e. it's still not a corpse)
			// the unit is already removed from map and from player's
			// unit list (=the unit went through LetUnitDie() which
			// calls RemoveUnit() and UnitLost()).  Such a unit should not
			// be put on player's unit list!  However, this state is not
			// easily detected from this place.  It seems that it is
			// characterized by
			// unit->CurrentAction()==UnitActionDie so we have to wait
			// until we parsed at least Unit::Orders[].
			Assert(type);
			unit->Init(*type);
			unit->Seen.Type = seentype;
			unit->Active = 0;
			unit->Removed = 0;
			Assert(UnitNumber(*unit) == slot);
		} else if (!strcmp(value, "current-sight-range")) {
			unit->CurrentSightRange = LuaToNumber(l, 2, j + 1);
		} else if (!strcmp(value, "refs")) {
			unit->Refs = LuaToNumber(l, 2, j + 1);
		} else if (!strcmp(value, "host-info")) {
			lua_rawgeti(l, 2, j + 1);
			if (!lua_istable(l, -1) || lua_rawlen(l, -1) != 4) {
				LuaError(l, "incorrect argument");
			}
			Vec2i pos;
			int w;
			int h;

			pos.x = LuaToNumber(l, -1, 1);
			pos.y = LuaToNumber(l, -1, 2);
			w = LuaToNumber(l, -1, 3);
			h = LuaToNumber(l, -1, 4);
			MapSight(*player, *unit, pos, w, h, unit->CurrentSightRange, MapMarkTileSight);
			// Detectcloak works in container
			if (unit->Type->BoolFlag[DETECTCLOAK_INDEX].value) {
				MapSight(*player, *unit, pos, w, h, unit->CurrentSightRange, MapMarkTileDetectCloak);
			}
			// Radar(Jammer) not.
			lua_pop(l, 1);
		} else if (!strcmp(value, "tile")) {
			lua_rawgeti(l, 2, j + 1);
			CclGetPos(l, &unit->tilePos.x , &unit->tilePos.y, -1);
			lua_pop(l, 1);
			unit->Offset = Map.getIndex(unit->tilePos);
		} else if (!strcmp(value, "seen-tile")) {
			lua_rawgeti(l, 2, j + 1);
			CclGetPos(l, &unit->Seen.tilePos.x , &unit->Seen.tilePos.y, -1);
			lua_pop(l, 1);
		} else if (!strcmp(value, "stats")) {
			unit->Stats = &type->Stats[LuaToNumber(l, 2, j + 1)];
		} else if (!strcmp(value, "pixel")) {
			lua_rawgeti(l, 2, j + 1);
			CclGetPos(l, &unit->IX , &unit->IY, -1);
			lua_pop(l, 1);
		} else if (!strcmp(value, "seen-pixel")) {
			lua_rawgeti(l, 2, j + 1);
			CclGetPos(l, &unit->Seen.IX , &unit->Seen.IY, -1);
			lua_pop(l, 1);
		} else if (!strcmp(value, "frame")) {
			unit->Frame = LuaToNumber(l, 2, j + 1);
		} else if (!strcmp(value, "seen")) {
			unit->Seen.Frame = LuaToNumber(l, 2, j + 1);
		} else if (!strcmp(value, "not-seen")) {
			unit->Seen.Frame = UnitNotSeen;
			--j;
		} else if (!strcmp(value, "direction")) {
			unit->Direction = LuaToNumber(l, 2, j + 1);
		} else if (!strcmp(value, "damage-type")) {
			unit->DamagedType = LuaToNumber(l, 2, j + 1);
		} else if (!strcmp(value, "attacked")) {
			// FIXME : unsigned long should be better handled
			unit->Attacked = LuaToNumber(l, 2, j + 1);
		} else if (!strcmp(value, "auto-repair")) {
			unit->AutoRepair = 1;
			--j;
		} else if (!strcmp(value, "burning")) {
			unit->Burning = 1;
			--j;
		} else if (!strcmp(value, "destroyed")) {
			unit->Destroyed = 1;
			--j;
		} else if (!strcmp(value, "removed")) {
			unit->Removed = 1;
			--j;
		} else if (!strcmp(value, "selected")) {
			unit->Selected = 1;
			--j;
		} else if (!strcmp(value, "summoned")) {
			// FIXME : unsigned long should be better handled
			unit->Summoned = LuaToNumber(l, 2, j + 1);
		} else if (!strcmp(value, "waiting")) {
			unit->Waiting = 1;
			--j;
		} else if (!strcmp(value, "mine-low")) {
			unit->MineLow = 1;
			--j;
		} else if (!strcmp(value, "rescued-from")) {
			unit->RescuedFrom = &Players[LuaToNumber(l, 2, j + 1)];
		} else if (!strcmp(value, "seen-by-player")) {
			const char *s = LuaToString(l, 2, j + 1);
			unit->Seen.ByPlayer = 0;
			for (int i = 0; i < PlayerMax && *s; ++i, ++s) {
				if (*s == '-' || *s == '_' || *s == ' ') {
					unit->Seen.ByPlayer &= ~(1 << i);
				} else {
					unit->Seen.ByPlayer |= (1 << i);
				}
			}
		} else if (!strcmp(value, "seen-destroyed")) {
			const char *s = LuaToString(l, 2, j + 1);
			unit->Seen.Destroyed = 0;
			for (int i = 0; i < PlayerMax && *s; ++i, ++s) {
				if (*s == '-' || *s == '_' || *s == ' ') {
					unit->Seen.Destroyed &= ~(1 << i);
				} else {
					unit->Seen.Destroyed |= (1 << i);
				}
			}
		} else if (!strcmp(value, "constructed")) {
			unit->Constructed = 1;
			--j;
		} else if (!strcmp(value, "seen-constructed")) {
			unit->Seen.Constructed = 1;
			--j;
		} else if (!strcmp(value, "seen-state")) {
			unit->Seen.State = LuaToNumber(l, 2, j + 1);
		} else if (!strcmp(value, "active")) {
			unit->Active = 1;
			--j;
		} else if (!strcmp(value, "ttl")) {
			// FIXME : unsigned long should be better handled
			unit->TTL = LuaToNumber(l, 2, j + 1);
		} else if (!strcmp(value, "threshold")) {
			// FIXME : unsigned long should be better handled
			unit->Threshold = LuaToNumber(l, 2, j + 1);
		} else if (!strcmp(value, "group-id")) {
			unit->GroupId = LuaToNumber(l, 2, j + 1);
		} else if (!strcmp(value, "last-group")) {
			unit->LastGroup = LuaToNumber(l, 2, j + 1);
		} else if (!strcmp(value, "resources-held")) {
			unit->ResourcesHeld = LuaToNumber(l, 2, j + 1);
		} else if (!strcmp(value, "current-resource")) {
			lua_rawgeti(l, 2, j + 1);
			lua_pushvalue(l, -1);
			unit->CurrentResource = CclGetResourceByName(l);
			lua_pop(l, 1);
		} else if (!strcmp(value, "pathfinder-input")) {
			lua_rawgeti(l, 2, j + 1);
			lua_pushvalue(l, -1);
			unit->pathFinderData->input.Load(l);
			lua_pop(l, 1);
		} else if (!strcmp(value, "pathfinder-output")) {
			lua_rawgeti(l, 2, j + 1);
			lua_pushvalue(l, -1);
			unit->pathFinderData->output.Load(l);
			lua_pop(l, 1);
		} else if (!strcmp(value, "wait")) {
			unit->Wait = LuaToNumber(l, 2, j + 1);
		} else if (!strcmp(value, "anim-data")) {
			lua_rawgeti(l, 2, j + 1);
			CAnimations::LoadUnitAnim(l, *unit, -1);
			lua_pop(l, 1);
		} else if (!strcmp(value, "wait-anim-data")) {
			lua_rawgeti(l, 2, j + 1);
			CAnimations::LoadWaitUnitAnim(l, *unit, -1);
			lua_pop(l, 1);
		} else if (!strcmp(value, "blink")) {
			unit->Blink = LuaToNumber(l, 2, j + 1);
		} else if (!strcmp(value, "moving")) {
			unit->Moving = 1;
			--j;
		} else if (!strcmp(value, "re-cast")) {
			unit->ReCast = 1;
			--j;
		} else if (!strcmp(value, "boarded")) {
			unit->Boarded = 1;
			--j;
		} else if (!strcmp(value, "next-worker")) {
			lua_rawgeti(l, 2, j + 1);
			lua_pushvalue(l, -1);
			unit->NextWorker = CclGetUnitFromRef(l);
			lua_pop(l, 1);
		} else if (!strcmp(value, "resource-workers")) {
			lua_rawgeti(l, 2, j + 1);
			lua_pushvalue(l, -1);
			unit->Resource.Workers = CclGetUnitFromRef(l);
			lua_pop(l, 1);
		} else if (!strcmp(value, "resource-assigned")) {
			lua_rawgeti(l, 2, j + 1);
			lua_pushvalue(l, -1);
			unit->Resource.Assigned = LuaToNumber(l, -1);
			lua_pop(l, 1);
		} else if (!strcmp(value, "resource-active")) {
			lua_rawgeti(l, 2, j + 1);
			lua_pushvalue(l, -1);
			unit->Resource.Active = LuaToNumber(l, -1);
			lua_pop(l, 1);
		} else if (!strcmp(value, "units-boarded-count")) {
			unit->BoardCount = LuaToNumber(l, 2, j + 1);
		} else if (!strcmp(value, "units-contained")) {
			int subargs;
			int k;
			lua_rawgeti(l, 2, j + 1);
			if (!lua_istable(l, -1)) {
				LuaError(l, "incorrect argument");
			}
			subargs = lua_rawlen(l, -1);
			for (k = 0; k < subargs; ++k) {
				lua_rawgeti(l, -1, k + 1);
				CUnit *u = CclGetUnitFromRef(l);
				lua_pop(l, 1);
				u->AddInContainer(*unit);
			}
			lua_pop(l, 1);
		} else if (!strcmp(value, "orders")) {
			lua_rawgeti(l, 2, j + 1);
			lua_pushvalue(l, -1);
			CclParseOrders(l, *unit);
			lua_pop(l, 1);
			// now we know unit's action so we can assign it to a player
			Assert(player != NULL);
			unit->AssignToPlayer(*player);
			if (unit->CurrentAction() == UnitActionBuilt) {
				DebugPrint("HACK: the building is not ready yet\n");
				// HACK: the building is not ready yet
				unit->Player->UnitTypesCount[type->Slot]--;
				if (unit->Active) {
					unit->Player->UnitTypesAiActiveCount[type->Slot]--;
				}
			}
		} else if (!strcmp(value, "critical-order")) {
			lua_rawgeti(l, 2, j + 1);
			lua_pushvalue(l, -1);
			CclParseOrder(l, *unit , &unit->CriticalOrder);
			lua_pop(l, 1);
		} else if (!strcmp(value, "saved-order")) {
			lua_rawgeti(l, 2, j + 1);
			lua_pushvalue(l, -1);
			CclParseOrder(l, *unit, &unit->SavedOrder);
			lua_pop(l, 1);
		} else if (!strcmp(value, "new-order")) {
			lua_rawgeti(l, 2, j + 1);
			lua_pushvalue(l, -1);
			CclParseOrder(l, *unit, &unit->NewOrder);
			lua_pop(l, 1);
		} else if (!strcmp(value, "goal")) {
			unit->Goal = &UnitManager->GetSlotUnit(LuaToNumber(l, 2, j + 1));
		} else if (!strcmp(value, "auto-cast")) {
			const char *s = LuaToString(l, 2, j + 1);
			Assert(SpellTypeByIdent(s));
			if (!unit->AutoCastSpell) {
				unit->AutoCastSpell = new char[SpellTypeTable.size()];
				memset(unit->AutoCastSpell, 0, SpellTypeTable.size());
			}
			unit->AutoCastSpell[SpellTypeByIdent(s)->Slot] = 1;
		} else if (!strcmp(value, "spell-cooldown")) {
			lua_rawgeti(l, 2, j + 1);
			if (!lua_istable(l, -1) || lua_rawlen(l, -1) != SpellTypeTable.size()) {
				LuaError(l, "incorrect argument");
			}
			if (!unit->SpellCoolDownTimers) {
				unit->SpellCoolDownTimers = new int[SpellTypeTable.size()];
				memset(unit->SpellCoolDownTimers, 0, SpellTypeTable.size() * sizeof(int));
			}
			for (size_t k = 0; k < SpellTypeTable.size(); ++k) {
				unit->SpellCoolDownTimers[k] = LuaToNumber(l, -1, k + 1);
			}
			lua_pop(l, 1);
		} else {
			const int index = UnitTypeVar.VariableNameLookup[value];// User variables
			if (index != -1) { // Valid index
				lua_rawgeti(l, 2, j + 1);
				DefineVariableField(l, unit->Variable + index, -1);
				lua_pop(l, 1);
				continue;
			}
			LuaError(l, "Unit: Unsupported tag: %s" _C_ value);
		}
	}

	// Unit may not have been assigned to a player before now. If not,
	// do so now. It is only assigned earlier if we have orders.
	// for loading of units from a MAP, and not a savegame, we won't
	// have orders for those units.  They should appear here as if
	// they were just created.
	if (!unit->Player) {
		Assert(player);
		unit->AssignToPlayer(*player);
		UpdateForNewUnit(*unit, 0);
	}

	//  Revealers are units that can see while removed
	if (unit->Removed && unit->Type->BoolFlag[REVEALER_INDEX].value) {
		MapMarkUnitSight(*unit);
	}

	if (!hadType && unit->Container) {
		// this unit was assigned to a container before it had a type, so we
		// need to actually add it now, since only with a type do we know the
		// BoardSize it takes up in the container
		CUnit *host = unit->Container;
		unit->Container = NULL;
		unit->AddInContainer(*host);
	}

	return 0;
}

MoveUnit


Move a unit on map.

@param l Lua state.

@return Returns the slot number of the made placed.

Example:

-- Create the unit
footman = CreateUnit("unit-footman", 0, {7, 4})
-- Move the unit to position 20 (x) and 10 (y)
MoveUnit(footman,{20,10})

/unit/script_unit.cpp:699 CclMoveUnit

static int CclMoveUnit(lua_State *l)
{
	LuaCheckArgs(l, 2);

	lua_pushvalue(l, 1);
	CUnit *unit = CclGetUnit(l);
	lua_pop(l, 1);

	Vec2i ipos;
	CclGetPos(l, &ipos.x, &ipos.y, 2);

	if (!unit->Removed) {
		unit->Remove(unit->Container);
	}

	if (UnitCanBeAt(*unit, ipos)) {
		unit->Place(ipos);
	} else {
		const int heading = SyncRand() % 256;

		unit->tilePos = ipos;
		DropOutOnSide(*unit, heading, NULL);
	}
	lua_pushvalue(l, 1);
	return 1;
}

RemoveUnit


Description

Remove unit from the map.

@param l Lua state.

@return Returns 1.

Example:

ogre = CreateUnit("unit-ogre", 0, {24, 89})

AddTrigger(
function() return (GameCycle > 150) end,
function()
RemoveUnit(ogre)
return false end -- end of function
)

/unit/script_unit.cpp:733 CclRemoveUnit

static int CclRemoveUnit(lua_State *l)
{
	LuaCheckArgs(l, 1);
	lua_pushvalue(l, 1);
	CUnit *unit = CclGetUnit(l);
	lua_pop(l, 1);
	if (unit) {
		unit->Remove(NULL);
		LetUnitDie(*unit);
	}
	lua_pushvalue(l, 1);
	return 1;
}

CreateUnit


Description

Create a unit and place it on the map

@param l Lua state.

@return Returns the slot number of the made unit.

Example:

CreateUnit("unit-human-transport", 1, {94, 0})

/unit/script_unit.cpp:793 CclCreateUnit

static int CclCreateUnit(lua_State *l)
{
	LuaCheckArgs(l, 3);

	lua_pushvalue(l, 1);
	CUnitType *unittype = CclGetUnitType(l);
	if (unittype == NULL) {
		LuaError(l, "Bad unittype");
	}
	lua_pop(l, 1);
	Vec2i ipos;
	CclGetPos(l, &ipos.x, &ipos.y, 3);

	lua_pushvalue(l, 2);
	const int playerno = TriggerGetPlayer(l);
	lua_pop(l, 1);
	if (playerno == -1) {
		printf("CreateUnit: You cannot use \"any\" in create-unit, specify a player\n");
		LuaError(l, "bad player");
		return 0;
	}
	if (Players[playerno].Type == PlayerTypes::PlayerNobody) {
		printf("CreateUnit: player %d does not exist\n", playerno);
		LuaError(l, "bad player");
		return 0;
	}
	CUnit *unit = MakeUnit(*unittype, &Players[playerno]);
	if (unit == NULL) {
		DebugPrint("Unable to allocate unit");
		return 0;
	} else {
		if (UnitCanBeAt(*unit, ipos)
			|| (unit->Type->Building && CanBuildUnitType(NULL, *unit->Type, ipos, 0))) {
			unit->Place(ipos);
		} else {
			const int heading = SyncRand() % 256;

			unit->tilePos = ipos;
			DropOutOnSide(*unit, heading, NULL);
		}
		UpdateForNewUnit(*unit, 0);

		lua_pushnumber(l, UnitNumber(*unit));
		return 1;
	}
}

TransformUnit


Description

'Upgrade' a unit in place to a unit of different type.

@param l Lua state.

@return Returns success.

Example:

-- Make a peon for player 5
peon = CreateUnit("unit-peon", 5, {58, 9})
-- The peon will be trasformed into a Grunt
TransformUnit(peon,"unit-grunt")

/unit/script_unit.cpp:824 CclTransformUnit

static int CclTransformUnit(lua_State *l)
{
	lua_pushvalue(l, 1);
	CUnit *targetUnit = CclGetUnit(l);
	lua_pop(l, 1);
	lua_pushvalue(l, 2);
	const CUnitType *unittype = TriggerGetUnitType(l);
	lua_pop(l, 1);
	if (unittype && targetUnit) {
		CommandUpgradeTo(*targetUnit, *(CUnitType*)unittype, 1, true);
	}
	lua_pushvalue(l, 1);
	return 1;
}

DamageUnit


Description

Damages unit, additionally using another unit as first's attacker

@param l Lua state.

@return Returns the slot number of the made unit.

Example:

-- Make a grunt for player 5
grunt = CreateUnit("unit-grunt", 5, {58, 8})
-- Damage the grunt with 15 points
DamageUnit(-1,grunt,15)

/unit/script_unit.cpp:858 CclDamageUnit

static int CclDamageUnit(lua_State *l)
{
	LuaCheckArgs(l, 3);

	const int attacker = LuaToNumber(l, 1);
	CUnit *attackerUnit = NULL;
	if (attacker != -1) {
		attackerUnit = &UnitManager->GetSlotUnit(attacker);
	}
	lua_pushvalue(l, 2);
	CUnit *targetUnit = CclGetUnit(l);
	lua_pop(l, 1);
	const int damage = LuaToNumber(l, 3);
	HitUnit(attackerUnit, *targetUnit, damage);

	return 1;
}

SetResourcesHeld


Set resources held by a unit

@param l Lua state.

/unit/script_unit.cpp:883 CclSetResourcesHeld

static int CclSetResourcesHeld(lua_State *l)
{
	LuaCheckArgs(l, 2);

	if (lua_isnil(l, 1)) {
		return 0;
	}

	lua_pushvalue(l, 1);
	CUnit *unit = CclGetUnit(l);
	lua_pop(l, 1);
	const int value = LuaToNumber(l, 2);
	unit->ResourcesHeld = value;
	unit->Variable[GIVERESOURCE_INDEX].Value = value;
	unit->Variable[GIVERESOURCE_INDEX].Max = value;
	unit->Variable[GIVERESOURCE_INDEX].Enable = 1;

	return 0;
}

SetTeleportDestination


Set teleport deastination for teleporter unit

@param l Lua state.

/unit/script_unit.cpp:908 CclSetTeleportDestination

static int CclSetTeleportDestination(lua_State *l)
{
	LuaCheckArgs(l, 2);

	lua_pushvalue(l, 1);
	CUnit *unit = CclGetUnit(l);
	lua_pop(l, 1);
	if (unit->Type->BoolFlag[TELEPORTER_INDEX].value == false) {
		LuaError(l, "Unit not a teleporter");
	}
	lua_pushvalue(l, 2);
	CUnit *dest = CclGetUnit(l);
	lua_pop(l, 1);
	if (dest->IsAliveOnMap()) {
		unit->Goal = dest;
	}

	return 0;
}

OrderUnit


Description

Order a unit

@param l Lua state.

OrderUnit(player, unit-type, start_loc, dest_loc, order)

Example:

-- Move transport from position x=94,y=0 to x=80,y=9
OrderUnit(1,"unit-human-transport",{94,0},{80,9},"move")

/unit/script_unit.cpp:992 CclOrderUnit

static int CclOrderUnit(lua_State *l)
{
	LuaCheckArgs(l, 5);

	lua_pushvalue(l, 1);
	const int plynr = TriggerGetPlayer(l);
	lua_pop(l, 1);
	lua_pushvalue(l, 2);
	const CUnitType *unittype = TriggerGetUnitType(l);
	lua_pop(l, 1);
	if (!lua_istable(l, 3)) {
		LuaError(l, "incorrect argument");
	}
	Vec2i pos1;
	pos1.x = LuaToNumber(l, 3, 1);
	pos1.y = LuaToNumber(l, 3, 2);

	Vec2i pos2;
	if (lua_rawlen(l, 3) == 4) {
		pos2.x = LuaToNumber(l, 3, 3);
		pos2.y = LuaToNumber(l, 3, 4);
	} else {
		pos2 = pos1;
	}
	if (!lua_istable(l, 4)) {
		LuaError(l, "incorrect argument");
	}
	Vec2i dpos1;
	Vec2i dpos2;
	dpos1.x = LuaToNumber(l, 4, 1);
	dpos1.y = LuaToNumber(l, 4, 2);
	if (lua_rawlen(l, 4) == 4) {
		dpos2.x = LuaToNumber(l, 4, 3);
		dpos2.y = LuaToNumber(l, 4, 4);
	} else {
		dpos2 = dpos1;
	}
	const char *order = LuaToString(l, 5);
	std::vector<CUnit *> table;
	Select(pos1, pos2, table);
	for (size_t i = 0; i != table.size(); ++i) {
		CUnit &unit = *table[i];

		if (unittype == ANY_UNIT
			|| (unittype == ALL_FOODUNITS && !unit.Type->Building)
			|| (unittype == ALL_BUILDINGS && unit.Type->Building)
			|| unittype == unit.Type) {
			if (plynr == -1 || plynr == unit.Player->Index) {
				if (!strcmp(order, "move")) {
					CommandMove(unit, (dpos1 + dpos2) / 2, 1);
				} else if (!strcmp(order, "stop")) {
					CommandStopUnit(unit); //Stop the unit
				} else if (!strcmp(order, "stand-ground")) {
					CommandStandGround(unit,0); //Stand and flush every order
				} else if (!strcmp(order, "attack")) {
					CUnit *attack = TargetOnMap(unit, dpos1, dpos2);
					CommandAttack(unit, (dpos1 + dpos2) / 2, attack, 1);
				} else if (!strcmp(order, "explore")) {
					CommandExplore(unit, 1);
				} else if (!strcmp(order, "patrol")) {
					CommandPatrolUnit(unit, (dpos1 + dpos2) / 2, 1);
				} else {
					LuaError(l, "Unsupported order: %s" _C_ order);
				}
			}
		}
	}
	return 0;
}

KillUnit


Description

Kill a unit

@param l Lua state.

@return Returns true if a unit was killed.

Example:

-- Kills an ogre controlled by player 3
KillUnit("unit-ogre", 3)

/unit/script_unit.cpp:1051 CclKillUnit

static int CclKillUnit(lua_State *l)
{
	LuaCheckArgs(l, 2);

	lua_pushvalue(l, 1);
	const CUnitType *unittype = TriggerGetUnitType(l);
	lua_pop(l, 1);
	const int plynr = TriggerGetPlayer(l);
	if (plynr == -1) {
		CUnitManager::Iterator it = std::find_if(UnitManager->begin(), UnitManager->end(), HasSameUnitTypeAs(unittype));

		if (it != UnitManager->end()) {
			LetUnitDie(**it);
			lua_pushboolean(l, 1);
			return 1;
		}
	} else {
		CPlayer &player = Players[plynr];
		std::vector<CUnit *>::iterator it = std::find_if(player.UnitBegin(), player.UnitEnd(), HasSameUnitTypeAs(unittype));

		if (it != player.UnitEnd()) {
			LetUnitDie(**it);
			lua_pushboolean(l, 1);
			return 1;
		}
	}
	lua_pushboolean(l, 0);
	return 1;
}

KillUnitAt


Description

Kill a unit at a location

@param l Lua state.

@return Returns the number of units killed.

Example:

-- Kill 8 peasants controlled by player 7 from position {27,1} to {34,5}
KillUnitAt("unit-peasant",7,8,{27,1},{34,5})

/unit/script_unit.cpp:1113 CclKillUnitAt

static int CclKillUnitAt(lua_State *l)
{
	LuaCheckArgs(l, 5);

	lua_pushvalue(l, 1);
	const CUnitType *unittype = TriggerGetUnitType(l);
	lua_pop(l, 1);
	lua_pushvalue(l, 2);
	int plynr = TriggerGetPlayer(l);
	lua_pop(l, 1);
	int q = LuaToNumber(l, 3);

	if (!lua_istable(l, 4) || !lua_istable(l, 5)) {
		LuaError(l, "incorrect argument");
	}
	Vec2i pos1;
	Vec2i pos2;
	CclGetPos(l, &pos1.x, &pos1.y, 4);
	CclGetPos(l, &pos2.x, &pos2.y, 5);
	if (pos1.x > pos2.x) {
		std::swap(pos1.x, pos2.x);
	}
	if (pos1.y > pos2.y) {
		std::swap(pos1.y, pos2.y);
	}

	std::vector<CUnit *> table;

	Select(pos1, pos2, table);

	int s = 0;
	for (std::vector<CUnit *>::iterator it = table.begin(); it != table.end() && s < q; ++it) {
		CUnit &unit = **it;

		if (unittype == ANY_UNIT
			|| (unittype == ALL_FOODUNITS && !unit.Type->Building)
			|| (unittype == ALL_BUILDINGS && unit.Type->Building)
			|| unittype == unit.Type) {
			if ((plynr == -1 || plynr == unit.Player->Index) && unit.IsAlive()) {
				LetUnitDie(unit);
				++s;
			}
		}
	}
	lua_pushnumber(l, s);
	return 1;
}

FindNextResource


Find the next reachable resource unit that gives resource starting from a worker.
Optional third argument is the range to search.

@param l Lua state.

Example:


peon = CreateUnit("unit-peon", 5, {58, 8})
goldmine = FindNextResource(peon, 0)

/unit/script_unit.cpp:1566 CclFindNextResource

static int CclFindNextResource(lua_State *l)
{
	const int nargs = lua_gettop(l);
	if (nargs < 2 || nargs > 3) {
		LuaError(l, "incorrect argument count");
	}

	lua_pushvalue(l, 1);
	CUnit *unit = CclGetUnit(l);
	lua_pop(l, 1);

	lua_pushvalue(l, 2);
	const int resource = CclGetResourceByName(l);
	lua_pop(l, 1);

	const int range = nargs == 3 ? LuaToNumber(l, 3) : 1000;

	CUnit *resourceUnit = UnitFindResource(*unit, *unit, range, resource);
	if (resourceUnit) {
		lua_pushnumber(l, UnitNumber(*unit));
	} else {
		lua_pushnil(l);
	}
	return 1;
}

GetUnits


Description

Get a player's units

@param l Lua state.

@return Array of units.

Example:

-- Get units from player 0
units = GetUnits(0)
for i, id_unit in ipairs(units) do
print(id_unit)
end

/unit/script_unit.cpp:1153 CclGetUnits

static int CclGetUnits(lua_State *l)
{
	LuaCheckArgs(l, 1);

	const int plynr = TriggerGetPlayer(l);

	lua_newtable(l);
	if (plynr == -1) {
		int i = 0;
		for (CUnitManager::Iterator it = UnitManager->begin(); it != UnitManager->end(); ++it, ++i) {
			const CUnit &unit = **it;
			lua_pushnumber(l, UnitNumber(unit));
			lua_rawseti(l, -2, i + 1);
		}
	} else {
		for (int i = 0; i < Players[plynr].GetUnitCount(); ++i) {
			lua_pushnumber(l, UnitNumber(Players[plynr].GetUnit(i)));
			lua_rawseti(l, -2, i + 1);
		}
	}
	return 1;
}

GetUnitsAroundUnit


Description

Get a player's units in rectangle box specified with 2 coordinates

@param l Lua state.

@return Array of units.

Example:

circlePower = CreateUnit("unit-circle-of-power", 15, {59, 4})
-- Get the units near the circle of power.
unitsOnCircle = GetUnitsAroundUnit(circle,1,true)

/unit/script_unit.cpp:1199 CclGetUnitsAroundUnit

static int CclGetUnitsAroundUnit(lua_State *l)
{
	const int nargs = lua_gettop(l);
	if (nargs != 2 && nargs != 3) {
		LuaError(l, "incorrect argument\n");
	}

	const int slot = LuaToNumber(l, 1);
	const CUnit &unit = UnitManager->GetSlotUnit(slot);
	const int range = LuaToNumber(l, 2);
	bool allUnits = false;
	if (nargs == 3) {
		allUnits = LuaToBoolean(l, 3);
	}
	lua_newtable(l);
	std::vector<CUnit *> table;
	if (allUnits) {
		SelectAroundUnit(unit, range, table, HasNotSamePlayerAs(Players[PlayerNumNeutral]));
	} else {
		SelectAroundUnit(unit, range, table, HasSamePlayerAs(*unit.Player));
	}
	size_t n = 0;
	for (size_t i = 0; i < table.size(); ++i) {
		if (table[i]->IsAliveOnMap()) {
			lua_pushnumber(l, UnitNumber(*table[i]));
			lua_rawseti(l, -2, ++n);
		}
	}
	return 1;
}

GetUnitBoolFlag



Get the value of the unit bool-flag.

@param l Lua state.

@return The value of the bool-flag of the unit.

/unit/script_unit.cpp:1224 CclGetUnitBoolFlag

static int CclGetUnitBoolFlag(lua_State *l)
{
	LuaCheckArgs(l, 2);

	lua_pushvalue(l, 1);
	const CUnit *unit = CclGetUnit(l);
	lua_pop(l, 1);

	const char *const value = LuaToString(l, 2);
	int index = UnitTypeVar.BoolFlagNameLookup[value];// User bool flags
	if (index == -1) {
		LuaError(l, "Bad bool-flag name '%s'\n" _C_ value);
	}
	lua_pushboolean(l, unit->Type->BoolFlag[index].value);
	return 1;
}

GetUnitVariable


Description

Get the value of the unit variable.

@param l Lua state.

@return The value of the variable of the unit.

Example:

-- Make a grunt for player 5
grunt = CreateUnit("unit-grunt", 5, {58, 8})
-- Take the name of the unit
unit_name = GetUnitVariable(grunt,"Name")
-- Take the player number based on the unit
player_type = GetUnitVariable(grunt,"PlayerType")
-- Take the value of the armor
armor_value = GetUnitVariable(grunt,"Armor")
-- Show the message in the game.
AddMessage(unit_name .. " " .. player_type .. " " .. armor_value)

/unit/script_unit.cpp:1347 CclGetUnitVariable

static int CclGetUnitVariable(lua_State *l)
{
	const int nargs = lua_gettop(l);
	Assert(nargs == 2 || nargs == 3);

	lua_pushvalue(l, 1);
	CUnit *unit = CclGetUnit(l);
	if (unit == NULL) {
		return 1;
	}
	UpdateUnitVariables(*unit);
	lua_pop(l, 1);

	const char *const value = LuaToString(l, 2);
	if (!strcmp(value, "RegenerationRate")) {
		lua_pushnumber(l, unit->Variable[HP_INDEX].Increase);
	} else if (!strcmp(value, "RegenerationFrequency")) {
		lua_pushnumber(l, std::max((int)unit->Variable[HP_INDEX].IncreaseFrequency, 1));
	} else if (!strcmp(value, "Ident")) {
		lua_pushstring(l, unit->Type->Ident.c_str());
	} else if (!strcmp(value, "ResourcesHeld")) {
		lua_pushnumber(l, unit->ResourcesHeld);
	} else if (!strcmp(value, "GiveResourceType")) {
		lua_pushnumber(l, unit->Type->GivesResource);
	} else if (!strcmp(value, "CurrentResource")) {
		lua_pushnumber(l, unit->CurrentResource);
	} else if (!strcmp(value, "Name")) {
		lua_pushstring(l, unit->Type->Name.c_str());
	} else if (!strcmp(value, "PlayerType")) {
		lua_pushstring(l, PlayerTypeNames[static_cast<int>(unit->Player->Type)].c_str());
	} else if (!strcmp(value, "TTLPercent")) {
		if (unit->Summoned && unit->TTL) {
			unsigned long time_lived = GameCycle - unit->Summoned;
			Assert(time_lived >= 0);
			unsigned long time_to_live = unit->TTL - unit->Summoned;
			Assert(time_to_live > 0);
			double pcnt = time_lived * 100.0 / time_to_live;
			int pcnt_i = (int)round(pcnt);
			lua_pushinteger(l, pcnt_i);
		} else {
			lua_pushinteger(l, -1);
		}
	} else if (!strcmp(value, "IndividualUpgrade")) {
		LuaCheckArgs(l, 3);
		std::string upgrade_ident = LuaToString(l, 3);
		if (CUpgrade::Get(upgrade_ident)) {
			lua_pushboolean(l, unit->IndividualUpgrades[CUpgrade::Get(upgrade_ident)->ID]);
		} else {
			LuaError(l, "Individual upgrade \"%s\" doesn't exist." _C_ upgrade_ident.c_str());
		}
		return 1;
	} else if (!strcmp(value, "Active")) {
		lua_pushboolean(l, unit->Active);
		return 1;
	} else if (!strcmp(value, "Idle")) {
		lua_pushboolean(l, unit->IsIdle());
		return 1;
	} else if (!strcmp(value, "PixelPos")) {
		PixelPos pos = unit->GetMapPixelPosCenter();
		lua_newtable(l);
		lua_pushnumber(l, pos.x);
		lua_setfield(l, -2, "x");
		lua_pushnumber(l, pos.y);
		lua_setfield(l, -2, "y");
		return 1;
	} else {
		int index = UnitTypeVar.VariableNameLookup[value];// User variables
		if (index == -1) {
			if (nargs == 2) {
				index = UnitTypeVar.BoolFlagNameLookup[value];
				if (index != -1) {
					lua_pushboolean(l, unit->Type->BoolFlag[index].value);
					return 1;
				}
			}
		}
		if (index == -1) {
			LuaError(l, "Bad variable name '%s'\n" _C_ value);
		}
		if (nargs == 2) {
			lua_pushnumber(l, unit->Variable[index].Value);
		} else {
			const char *const type = LuaToString(l, 3);
			if (!strcmp(type, "Value")) {
				lua_pushnumber(l, unit->Variable[index].Value);
			} else if (!strcmp(type, "Max")) {
				lua_pushnumber(l, unit->Variable[index].Max);
			} else if (!strcmp(type, "Increase")) {
				lua_pushnumber(l, unit->Variable[index].Increase);
			} else if (!strcmp(type, "IncreaseFrequency")) {
				lua_pushnumber(l, std::max((int)unit->Variable[index].IncreaseFrequency, 1));
			} else if (!strcmp(type, "Enable")) {
				lua_pushnumber(l, unit->Variable[index].Enable);
			} else {
				LuaError(l, "Bad variable type '%s'\n" _C_ type);
			}
		}
	}
	return 1;
}

SetUnitVariable


Description

Set the value of the unit variable.

@param l Lua state.

@return The new value of the unit.

Example:

-- Create a blacksmith for player 2
blacksmith = CreateUnit("unit-human-blacksmith", 2, {66, 71})
-- Specify the amount of hit points to assign to the blacksmith
SetUnitVariable(blacksmith,"HitPoints",344)
-- Set the blacksmiths color to the color of player 4
SetUnitVariable(blacksmith,"Color",4)

/unit/script_unit.cpp:1489 CclSetUnitVariable

static int CclSetUnitVariable(lua_State *l)
{
	const int nargs = lua_gettop(l);
	Assert(nargs >= 3 && nargs <= 5);

	lua_pushvalue(l, 1);
	CUnit *unit = CclGetUnit(l);
	lua_pop(l, 1);
	const char *const name = LuaToString(l, 2);
	int value = 0;
	if (!strcmp(name, "Player")) {
		value = LuaToNumber(l, 3);
		unit->ChangeOwner(Players[value]);
	} else if (!strcmp(name, "Color")) {
		if (lua_isstring(l, 3)) {
			const char *colorName = LuaToString(l, 3);
			for (size_t i = 0; i < PlayerColorNames.size(); i++) {
				if (PlayerColorNames[i] == colorName) {
					unit->Colors = i;
					break;
				}
			}
		} else if (lua_isnil(l, 3)) {
			unit->Colors = -1;
		} else {
			value = LuaToNumber(l, 3);
			unit->Colors = value;
		}
	} else if (!strcmp(name, "TTL")) {
		value = LuaToNumber(l, 3);
		unit->TTL = GameCycle + value;
	} else if (!strcmp(name, "Summoned")) {
		value = LuaToNumber(l, 3);
		unit->Summoned = value;
	} else if (!strcmp(name, "RegenerationRate")) {
		value = LuaToNumber(l, 3);
		unit->Variable[HP_INDEX].Increase = std::min(unit->Variable[HP_INDEX].Max, value);
	} else if (!strcmp(name, "RegenerationFrequency")) {
		value = LuaToNumber(l, 3);
		unit->Variable[HP_INDEX].IncreaseFrequency = value;
		if (unit->Variable[HP_INDEX].IncreaseFrequency != value) {
			LuaError(l, "RegenerationFrequency out of range!");
		}
	} else if (!strcmp(name, "IndividualUpgrade")) {
		LuaCheckArgs(l, 4);
		std::string upgrade_ident = LuaToString(l, 3);
		bool has_upgrade = LuaToBoolean(l, 4);
		if (CUpgrade::Get(upgrade_ident)) {
			if (has_upgrade && unit->IndividualUpgrades[CUpgrade::Get(upgrade_ident)->ID] == false) {
				IndividualUpgradeAcquire(*unit, CUpgrade::Get(upgrade_ident));
			} else if (!has_upgrade && unit->IndividualUpgrades[CUpgrade::Get(upgrade_ident)->ID]) {
				IndividualUpgradeLost(*unit, CUpgrade::Get(upgrade_ident));
			}
		} else {
			LuaError(l, "Individual upgrade \"%s\" doesn't exist." _C_ upgrade_ident.c_str());
		}
	} else if (!strcmp(name, "Active")) {
		bool ai_active = LuaToBoolean(l, 3);
		if (ai_active != unit->Active) {
			if (ai_active) {
				unit->Player->UnitTypesAiActiveCount[unit->Type->Slot]++;
			} else {
				unit->Player->UnitTypesAiActiveCount[unit->Type->Slot]--;
				if (unit->Player->UnitTypesAiActiveCount[unit->Type->Slot] < 0) { // if unit AI active count is negative, something wrong happened
					fprintf(stderr, "Player %d has a negative %s AI active count of %d.\n", unit->Player->Index, unit->Type->Ident.c_str(), unit->Player->UnitTypesAiActiveCount[unit->Type->Slot]);
				}
			}
		}
		unit->Active = ai_active;
	} else {
		const int index = UnitTypeVar.VariableNameLookup[name];// User variables
		if (index == -1) {
			LuaError(l, "Bad variable name '%s'\n" _C_ name);
		}
		value = LuaToNumber(l, 3);
		bool stats = false;
		if (nargs == 5) {
			stats = LuaToBoolean(l, 5);
		}
		if (stats) { // stat variables
			const char *const type = LuaToString(l, 4);
			if (!strcmp(type, "Value")) {
				unit->Stats->Variables[index].Value = std::min(unit->Stats->Variables[index].Max, value);
			} else if (!strcmp(type, "Max")) {
				unit->Stats->Variables[index].Max = value;
			} else if (!strcmp(type, "Increase")) {
				unit->Stats->Variables[index].Increase = value;
			} else if (!strcmp(type, "IncreaseFrequency")) {
				unit->Stats->Variables[index].IncreaseFrequency = value;
				if (unit->Stats->Variables[index].IncreaseFrequency != value) {
					LuaError(l, "%s.IncreaseFrequency out of range!" _C_ type);
				}
			} else if (!strcmp(type, "Enable")) {
				unit->Stats->Variables[index].Enable = value;
			} else {
				LuaError(l, "Bad variable type '%s'\n" _C_ type);
			}
		} else if (nargs == 3) {
			unit->Variable[index].Value = std::min(unit->Variable[index].Max, value);
		} else {
			const char *const type = LuaToString(l, 4);
			if (!strcmp(type, "Value")) {
				unit->Variable[index].Value = std::min(unit->Variable[index].Max, value);
			} else if (!strcmp(type, "Max")) {
				unit->Variable[index].Max = value;
			} else if (!strcmp(type, "Increase")) {
				unit->Variable[index].Increase = value;
			} else if (!strcmp(type, "IncreaseFrequency")) {
				unit->Variable[index].IncreaseFrequency = value;
				if (unit->Variable[index].IncreaseFrequency != value) {
					LuaError(l, "%s.IncreaseFrequency out of range!" _C_ type);
				}
			} else if (!strcmp(type, "Enable")) {
				unit->Variable[index].Enable = value;
			} else {
				LuaError(l, "Bad variable type '%s'\n" _C_ type);
			}
		}
	}
	lua_pushnumber(l, value);
	return 1;
}

SlotUsage


Get the usage of unit slots during load to allocate memory

@param l Lua state.

/unit/script_unit.cpp:1500 CclSlotUsage

static int CclSlotUsage(lua_State *l)
{
	UnitManager->Load(l);
	return 0;
}

SelectSingleUnit


Description

Select a single unit

@param l Lua state.

@return 0, meaning the unit is selected.

Example:

-- Make the hero unit Grom Hellscream for player 5
grom = CreateUnit("unit-beast-cry", 5, {58, 8})
-- Select only the unit Grom Hellscream
SelectSingleUnit(grom)

/unit/script_unit.cpp:1528 CclSelectSingleUnit

static int CclSelectSingleUnit(lua_State *l)
{
	const int nargs = lua_gettop(l);
	Assert(nargs == 1);
	lua_pushvalue(l, 1);
	CUnit *unit = CclGetUnit(l);
	lua_pop(l, 1);
	SelectSingleUnit(*unit);
	SelectionChanged();
	return 0;
}

EnableSimplifiedAutoTargeting


Enable/disable simplified auto targeting

@param l Lua state.

@return 0 for success, 1 for wrong type;

/unit/script_unit.cpp:1586 CclEnableSimplifiedAutoTargeting

static int CclEnableSimplifiedAutoTargeting(lua_State *l)
{
	LuaCheckArgs(l, 1);
	const bool isSimplified = LuaToBoolean(l, 1);
	if (!IsNetworkGame()) {
		GameSettings.SimplifiedAutoTargeting = isSimplified;
	} else {
		NetworkSendExtendedCommand(ExtendedMessageAutoTargetingDB, 
								   int(isSimplified), 0, 0, 0, 0);
	}
	return 0;
}


/unit/unit_draw.cpp
DefineSprites


Define the sprite to show variables.

@param l Lua_state

/unit/unit_draw.cpp:357 CclDefineSprites

static int CclDefineSprites(lua_State *l)
{
	const int args = lua_gettop(l);

	for (int i = 0; i < args; ++i) {
		Decoration deco;

		lua_pushnil(l);
		const char *name = NULL;// name of the current sprite.
		while (lua_next(l, i + 1)) {
			const char *key = LuaToString(l, -2); // key name
			if (!strcmp(key, "Name")) {
				name = LuaToString(l, -1);
			} else if (!strcmp(key, "File")) {
				deco.File = LuaToString(l, -1);
			} else if (!strcmp(key, "Offset")) {
				CclGetPos(l, &deco.HotPos.x, &deco.HotPos.y);
			} else if (!strcmp(key, "Size")) {
				CclGetPos(l, &deco.Width, &deco.Height);
			} else { // Error.
				LuaError(l, "incorrect field '%s' for the DefineSprite." _C_ key);
			}
			lua_pop(l, 1); // pop the value;
		}
		if (name == NULL) {
			LuaError(l, "CclDefineSprites requires the Name flag for sprite.");
		}
		int index = GetSpriteIndex(name); // Index of the Sprite.
		if (index == -1) { // new sprite.
			index = DecoSprite.SpriteArray.size();
			DecoSprite.Name.push_back(name);
			DecoSprite.SpriteArray.push_back(deco);
		} else {
			DecoSprite.SpriteArray[index].File.clear();
			DecoSprite.SpriteArray[index] = deco;
		}
		// Now verify validity.
		if (DecoSprite.SpriteArray[index].File.empty()) {
			LuaError(l, "CclDefineSprites requires the File flag for sprite.");
		}
		// FIXME check if file is valid with good size ?
	}
	return 0;
}


/unit/script_unittype.cpp
DefineUnitType


Description

Parse unit-type.

@param l Lua state.

Example:

DefineUnitType("unit-silvermoon-archer", { Name = _("Silvermoon Archer"),
Image = {"file", "human/units/elven_archer.png", "size", {72, 72}},
Animations = "animations-archer", Icon = "icon-archer",
Costs = {"time", 70, "gold", 500, "wood", 50},
Speed = 10,
HitPoints = 45,
DrawLevel = 40,
TileSize = {1, 1}, BoxSize = {33, 33},
SightRange = 6, ComputerReactionRange = 7, PersonReactionRange = 6,
BasicDamage = 4, PiercingDamage = 6, Missile = "missile-arrow",
MaxAttackRange = 4,
Priority = 75,
Points = 60,
Demand = 1,
Corpse = "unit-human-dead-body",
Type = "land",
RightMouseAction = "attack",
CanAttack = true,
CanTargetLand = true, CanTargetSea = true, CanTargetAir = true,
LandUnit = true,
organic = true,
SelectableByRectangle = true,
Sounds = {
"selected", "archer-selected",
"acknowledge", "archer-acknowledge",
"ready", "archer-ready",
"help", "basic human voices help 1",
"dead", "basic human voices dead"} } )

/unit/script_unittype.cpp:1235 CclDefineUnitType

static int CclDefineUnitType(lua_State *l)
{
	LuaCheckArgs(l, 2);
	if (!lua_istable(l, 2)) {
		LuaError(l, "incorrect argument");
	}

	// Slot identifier
	const char *str = LuaToString(l, 1);
	CUnitType *type = UnitTypeByIdent(str);

	constexpr int redefineSprite = 2;

	int redefine;
	if (type) {
		redefine = 1;
		DebugPrint("Redefining unit-type '%s'\n" _C_ str);
	} else {
		type = NewUnitTypeSlot(str);
		redefine = 0;
		type->NumDirections = 0;
		type->Flip = 1;
	}

	//  Parse the list: (still everything could be changed!)
	for (lua_pushnil(l); lua_next(l, 2); lua_pop(l, 1)) {
		const char *value = LuaToString(l, -2);
		if (!strcmp(value, "Name")) {
			type->Name = LuaToString(l, -1);
		} else if (!strcmp(value, "Image")) {
			if (!lua_istable(l, -1)) {
				LuaError(l, "incorrect argument");
			}
			int subargs = lua_rawlen(l, -1);
			for (int k = 0; k < subargs; ++k) {
				value = LuaToString(l, -1, k + 1);
				++k;

				if (!strcmp(value, "file")) {
					type->File = LuaToString(l, -1, k + 1);
				} else if (!strcmp(value, "alt-file")) {
					type->AltFile = LuaToString(l, -1, k + 1);
				} else if (!strcmp(value, "size")) {
					lua_rawgeti(l, -1, k + 1);
					CclGetPos(l, &type->Width, &type->Height);
					lua_pop(l, 1);
				} else {
					LuaError(l, "Unsupported image tag: %s" _C_ value);
				}
			}
			if (redefine) {
				if (type->Sprite && type->Sprite->File != type->File) {
					redefine |= redefineSprite;
					CGraphic::Free(type->Sprite);
					type->Sprite = NULL;
				}
				if (type->AltSprite && type->AltSprite->File != type->AltFile) {
					redefine |= redefineSprite;
					CGraphic::Free(type->AltSprite);
					type->AltSprite = NULL;
				}
				if (redefine && type->ShadowSprite) {
					redefine |= redefineSprite;
					CGraphic::Free(type->ShadowSprite);
					type->ShadowSprite = NULL;
				}
			}
			if (type->ShadowFile == shadowMarker) {
				type->ShadowFile = type->File;
				if (type->ShadowWidth == 0 && type->ShadowHeight == 0) {
					type->ShadowWidth = type->Width;
					type->ShadowHeight = type->Height;
				}
			}
		} else if (!strcmp(value, "Shadow")) {
			// default to same spritemap as unit
			if (type->File.length() > 0) {
				type->ShadowFile = type->File;
				type->ShadowWidth = type->Width;
				type->ShadowHeight = type->Height;
			} else {
				type->ShadowFile = shadowMarker;
			}
			if (!lua_istable(l, -1)) {
				LuaError(l, "incorrect argument");
			}
			const int subargs = lua_rawlen(l, -1);
			for (int k = 0; k < subargs; ++k) {
				value = LuaToString(l, -1, k + 1);
				++k;

				if (!strcmp(value, "file")) {
					type->ShadowFile = LuaToString(l, -1, k + 1);
				} else if (!strcmp(value, "size")) {
					lua_rawgeti(l, -1, k + 1);
					CclGetPos(l, &type->ShadowWidth, &type->ShadowHeight);
					lua_pop(l, 1);
				} else if (!strcmp(value, "offset")) {
					lua_rawgeti(l, -1, k + 1);
					CclGetPos(l, &type->ShadowOffsetX, &type->ShadowOffsetY);
					lua_pop(l, 1);
				} else if (!strcmp(value, "sprite-frame")) {
					type->ShadowSpriteFrame = LuaToNumber(l, -1, k + 1);
				} else if (!strcmp(value, "scale")) {
					type->ShadowScale = LuaToNumber(l, -1, k + 1);
				} else {
					LuaError(l, "Unsupported shadow tag: %s" _C_ value);
				}
			}
			if (redefine && type->ShadowSprite) {
				redefine |= redefineSprite;
				CGraphic::Free(type->ShadowSprite);
				type->ShadowSprite = NULL;
			}
		} else if (!strcmp(value, "Offset")) {
			CclGetPos(l, &type->OffsetX, &type->OffsetY);
		} else if (!strcmp(value, "Flip")) {
			type->Flip = LuaToBoolean(l, -1);
		} else if (!strcmp(value, "Animations")) {
			type->Animations = AnimationsByIdent(LuaToString(l, -1));
			if (!type->Animations) {
				DebugPrint("Warning animation '%s' not found\n" _C_ LuaToString(l, -1));
			}
		} else if (!strcmp(value, "Icon")) {
			type->Icon.Name = LuaToString(l, -1);
			type->Icon.Icon = NULL;
		} else if (!strcmp(value, "Portrait")) {
#ifdef USE_MNG
			if (!lua_istable(l, -1)) {
				LuaError(l, "incorrect argument");
			}
			const int subargs = lua_rawlen(l, -1);
			int number = 0;
			for (int k = 0; k < subargs; ++k) {
				const char *s = LuaToString(l, -1, k + 1);
				if (strcmp("talking", s)) {
					number++;
				}
			}
			type->Portrait.Num = number;
			type->Portrait.Talking = 0;
			type->Portrait.Files = new std::string[type->Portrait.Num];
			type->Portrait.Mngs = new Mng *[type->Portrait.Num];
			memset(type->Portrait.Mngs, 0, type->Portrait.Num * sizeof(Mng *));
			for (int k = 0; k < subargs; ++k) {
				const char *s = LuaToString(l, -1, k + 1);
				if (!strcmp("talking", s)) {
					type->Portrait.Talking = k;
				} else {
					type->Portrait.Files[k - (type->Portrait.Talking ? 1 : 0)] = s;
				}
			}
#endif
		} else if (!strcmp(value, "Costs")) {
			if (!lua_istable(l, -1)) {
				LuaError(l, "incorrect argument");
			}
			const int subargs = lua_rawlen(l, -1);
			for (int k = 0; k < subargs; ++k) {
				lua_rawgeti(l, -1, k + 1);
				const int res = CclGetResourceByName(l);
				lua_pop(l, 1);
				++k;
				type->DefaultStat.Costs[res] = LuaToNumber(l, -1, k + 1);
			}
		} else if (!strcmp(value, "Storing")) {
			if (!lua_istable(l, -1)) {
				LuaError(l, "incorrect argument");
			}
			const int subargs = lua_rawlen(l, -1);
			for (int k = 0; k < subargs; ++k) {
				lua_rawgeti(l, -1, k + 1);
				const int res = CclGetResourceByName(l);
				lua_pop(l, 1);
				++k;
				type->DefaultStat.Storing[res] = LuaToNumber(l, -1, k + 1);
			}
		} else if (!strcmp(value, "ImproveProduction")) {
			if (!lua_istable(l, -1)) {
				LuaError(l, "incorrect argument");
			}
			const int subargs = lua_rawlen(l, -1);
			for (int k = 0; k < subargs; ++k) {
				lua_rawgeti(l, -1, k + 1);
				const int res = CclGetResourceByName(l);
				lua_pop(l, 1);
				++k;
				type->DefaultStat.ImproveIncomes[res] = DefaultIncomes[res] + LuaToNumber(l, -1, k + 1);
			}
		} else if (!strcmp(value, "Construction")) {
			// FIXME: What if constructions aren't yet loaded?
			type->Construction = ConstructionByIdent(LuaToString(l, -1));
		} else if (!strcmp(value, "DrawLevel")) {
			type->DrawLevel = LuaToNumber(l, -1);
		} else if (!strcmp(value, "MaxOnBoard")) {
			type->MaxOnBoard = LuaToNumber(l, -1);
		} else if (!strcmp(value, "BoardSize")) {
			type->BoardSize = LuaToNumber(l, -1);
		} else if (!strcmp(value, "ButtonLevelForTransporter")) {
			type->ButtonLevelForTransporter = LuaToNumber(l, -1);
		} else if (!strcmp(value, "StartingResources")) {
			type->StartingResources = LuaToNumber(l, -1);
		} else if (!strcmp(value, "RegenerationRate")) {
			type->DefaultStat.Variables[HP_INDEX].Increase = LuaToNumber(l, -1);
		} else if (!strcmp(value, "RegenerationFrequency")) {
			int value = LuaToNumber(l, -1);
			type->DefaultStat.Variables[HP_INDEX].IncreaseFrequency = value;
			if (type->DefaultStat.Variables[HP_INDEX].IncreaseFrequency != value) {
				LuaError(l, "RegenerationFrequency out of range!");
			}
		} else if (!strcmp(value, "BurnPercent")) {
			type->BurnPercent = LuaToNumber(l, -1);
		} else if (!strcmp(value, "BurnDamageRate")) {
			type->BurnDamageRate = LuaToNumber(l, -1);
		} else if (!strcmp(value, "PoisonDrain")) {
			type->PoisonDrain = LuaToNumber(l, -1);
		} else if (!strcmp(value, "ShieldPoints")) {
			if (lua_istable(l, -1)) {
				DefineVariableField(l, type->DefaultStat.Variables + SHIELD_INDEX, -1);
			} else if (lua_isnumber(l, -1)) {
				type->DefaultStat.Variables[SHIELD_INDEX].Max = LuaToNumber(l, -1);
				type->DefaultStat.Variables[SHIELD_INDEX].Value = 0;
				type->DefaultStat.Variables[SHIELD_INDEX].Increase = 1;
				type->DefaultStat.Variables[SHIELD_INDEX].Enable = 1;
			}
		} else if (!strcmp(value, "TileSize")) {
			CclGetPos(l, &type->TileWidth, &type->TileHeight);
		} else if (!strcmp(value, "NeutralMinimapColor")) {
			type->NeutralMinimapColorRGB.Parse(l);
		} else if (!strcmp(value, "Neutral")) {
			type->Neutral = LuaToBoolean(l, -1);
		} else if (!strcmp(value, "BoxSize")) {
			CclGetPos(l, &type->BoxWidth, &type->BoxHeight);
		} else if (!strcmp(value, "BoxOffset")) {
			CclGetPos(l, &type->BoxOffsetX, &type->BoxOffsetY);
		} else if (!strcmp(value, "NumDirections")) {
			type->NumDirections = LuaToNumber(l, -1);
		} else if (!strcmp(value, "ComputerReactionRange")) {
			type->ReactRangeComputer = LuaToNumber(l, -1);
		} else if (!strcmp(value, "PersonReactionRange")) {
			type->ReactRangePerson = LuaToNumber(l, -1);
		} else if (!strcmp(value, "Missile")) {
			type->Missile.Name = LuaToString(l, -1);
			type->Missile.Missile = NULL;
		} else if (!strcmp(value, "MinAttackRange")) {
			type->MinAttackRange = LuaToNumber(l, -1);
		} else if (!strcmp(value, "MaxAttackRange")) {
			type->DefaultStat.Variables[ATTACKRANGE_INDEX].Value = LuaToNumber(l, -1);
			type->DefaultStat.Variables[ATTACKRANGE_INDEX].Max = LuaToNumber(l, -1);
			type->DefaultStat.Variables[ATTACKRANGE_INDEX].Enable = 1;
		} else if (!strcmp(value, "MaxHarvesters")) {
			type->DefaultStat.Variables[MAXHARVESTERS_INDEX].Value = LuaToNumber(l, -1);
			type->DefaultStat.Variables[MAXHARVESTERS_INDEX].Max = LuaToNumber(l, -1);
		} else if (!strcmp(value, "Priority")) {
			type->DefaultStat.Variables[PRIORITY_INDEX].Value  = LuaToNumber(l, -1);
			type->DefaultStat.Variables[PRIORITY_INDEX].Max  = LuaToNumber(l, -1);
		} else if (!strcmp(value, "AnnoyComputerFactor")) {
			type->AnnoyComputerFactor = LuaToNumber(l, -1);
		} else if (!strcmp(value, "AiAdjacentRange")) {
			type->AiAdjacentRange = LuaToNumber(l, -1);
		} else if (!strcmp(value, "DecayRate")) {
			type->DecayRate = LuaToNumber(l, -1);
		} else if (!strcmp(value, "Corpse")) {
			type->CorpseName = LuaToString(l, -1);
			type->CorpseType = NULL;
		} else if (!strcmp(value, "DamageType")) {
			value = LuaToString(l, -1);
			//int check = ExtraDeathIndex(value);
			type->DamageType = value;
		} else if (!strcmp(value, "ExplodeWhenKilled")) {
			type->ExplodeWhenKilled = 1;
			type->Explosion.Name = LuaToString(l, -1);
			type->Explosion.Missile = NULL;
		} else if (!strcmp(value, "TeleportCost")) {
			type->TeleportCost = LuaToNumber(l, -1);
		} else if (!strcmp(value, "TeleportEffectIn")) {
			type->TeleportEffectIn = new LuaCallback(l, -1);
		} else if (!strcmp(value, "TeleportEffectOut")) {
			type->TeleportEffectOut = new LuaCallback(l, -1);
		} else if (!strcmp(value, "OnDeath")) {
			type->OnDeath = new LuaCallback(l, -1);
		} else if (!strcmp(value, "OnHit")) {
			type->OnHit = new LuaCallback(l, -1);
		} else if (!strcmp(value, "OnEachCycle")) {
			type->OnEachCycle = new LuaCallback(l, -1);
		} else if (!strcmp(value, "OnEachSecond")) {
			type->OnEachSecond = new LuaCallback(l, -1);
		} else if (!strcmp(value, "OnInit")) {
			type->OnInit = new LuaCallback(l, -1);
		} else if (!strcmp(value, "OnReady")) {
			type->OnReady = new LuaCallback(l, -1);
		} else if (!strcmp(value, "Type")) {
			value = LuaToString(l, -1);
			if (!strcmp(value, "land")) {
				type->UnitType = UnitTypeLand;
			} else if (!strcmp(value, "fly")) {
				type->UnitType = UnitTypeFly;
			} else if (!strcmp(value, "naval")) {
				type->UnitType = UnitTypeNaval;
			} else {
				LuaError(l, "Unsupported Type: %s" _C_ value);
			}
		} else if (!strcmp(value, "MissileOffsets")) {
			if (!lua_istable(l, -1)) {
				LuaError(l, "incorrect argument");
			}
			const int subargs = lua_rawlen(l, -1);
			for (int k = 0; k < subargs; ++k) {
				lua_rawgeti(l, -1, k + 1);
				if (!lua_istable(l, -1) || lua_rawlen(l, -1) != UnitSides) {
					LuaError(l, "incorrect argument");
				}
				for (int m = 0; m < UnitSides; ++m) {
					lua_rawgeti(l, -1, m + 1);
					CclGetPos(l, &type->MissileOffsets[m][k].x, &type->MissileOffsets[m][k].y);
					lua_pop(l, 1);
				}
				lua_pop(l, 1);
			}
		} else if (!strcmp(value, "Impact")) {
			if (!lua_istable(l, -1)) {
				LuaError(l, "incorrect argument");
			}
			const int subargs = lua_rawlen(l, -1);
			for (int k = 0; k < subargs; ++k) {
				const char *dtype = LuaToString(l, -1, k + 1);
				++k;

				if (!strcmp(dtype, "general")) {
					type->Impact[ANIMATIONS_DEATHTYPES].Name = LuaToString(l, -1, k + 1);
					type->Impact[ANIMATIONS_DEATHTYPES].Missile = NULL;
				} else if (!strcmp(dtype, "shield")) {
					type->Impact[ANIMATIONS_DEATHTYPES + 1].Name = LuaToString(l, -1, k + 1);
					type->Impact[ANIMATIONS_DEATHTYPES + 1].Missile = NULL;
				} else {
					int num = 0;
					for (; num < ANIMATIONS_DEATHTYPES; ++num) {
						if (dtype == ExtraDeathTypes[num]) {
							break;
						}
					}
					if (num == ANIMATIONS_DEATHTYPES) {
						LuaError(l, "Death type not found: %s" _C_ dtype);
					} else {
						type->Impact[num].Name = LuaToString(l, -1, k + 1);
						type->Impact[num].Missile = NULL;
					}
				}
			}
		} else if (!strcmp(value, "RightMouseAction")) {
			value = LuaToString(l, -1);
			if (!strcmp(value, "none")) {
				type->MouseAction = MouseActionNone;
			} else if (!strcmp(value, "attack")) {
				type->MouseAction = MouseActionAttack;
			} else if (!strcmp(value, "move")) {
				type->MouseAction = MouseActionMove;
			} else if (!strcmp(value, "harvest")) {
				type->MouseAction = MouseActionHarvest;
			} else if (!strcmp(value, "spell-cast")) {
				type->MouseAction = MouseActionSpellCast;
			} else if (!strcmp(value, "sail")) {
				type->MouseAction = MouseActionSail;
			} else {
				LuaError(l, "Unsupported RightMouseAction: %s" _C_ value);
			}
		} else if (!strcmp(value, "CanAttack")) {
			type->CanAttack = LuaToBoolean(l, -1);
		} else if (!strcmp(value, "RepairRange")) {
			type->RepairRange = LuaToNumber(l, -1);
		} else if (!strcmp(value, "RepairHp")) {
			type->RepairHP = LuaToNumber(l, -1);
		} else if (!strcmp(value, "RepairCosts")) {
			if (!lua_istable(l, -1)) {
				LuaError(l, "incorrect argument");
			}
			const int subargs = lua_rawlen(l, -1);
			for (int k = 0; k < subargs; ++k) {
				lua_rawgeti(l, -1, k + 1);
				const int res = CclGetResourceByName(l);
				lua_pop(l, 1);
				++k;
				type->RepairCosts[res] = LuaToNumber(l, -1, k + 1);
			}
		} else if (!strcmp(value, "CanTargetLand")) {
			if (LuaToBoolean(l, -1)) {
				type->CanTarget |= CanTargetLand;
			} else {
				type->CanTarget &= ~CanTargetLand;
			}
		} else if (!strcmp(value, "CanTargetSea")) {
			if (LuaToBoolean(l, -1)) {
				type->CanTarget |= CanTargetSea;
			} else {
				type->CanTarget &= ~CanTargetSea;
			}
		} else if (!strcmp(value, "CanTargetAir")) {
			if (LuaToBoolean(l, -1)) {
				type->CanTarget |= CanTargetAir;
			} else {
				type->CanTarget &= ~CanTargetAir;
			}
		} else if (!strcmp(value, "Building")) {
			type->Building = LuaToBoolean(l, -1);
		} else if (!strcmp(value, "BuildingRules")) {
			if (!lua_istable(l, -1)) {
				LuaError(l, "incorrect argument");
			}
			const int subargs = lua_rawlen(l, -1);
			// Free any old restrictions if they are redefined
			for (std::vector<CBuildRestriction *>::iterator b = type->BuildingRules.begin();
				 b != type->BuildingRules.end(); ++b) {
				delete *b;
			}
			type->BuildingRules.clear();
			for (int k = 0; k < subargs; ++k) {
				lua_rawgeti(l, -1, k + 1);
				if (!lua_istable(l, -1)) {
					LuaError(l, "incorrect argument");
				}
				ParseBuildingRules(l, type->BuildingRules);
				lua_pop(l, 1);
			}
		} else if (!strcmp(value, "AiBuildingRules")) {
			if (!lua_istable(l, -1)) {
				LuaError(l, "incorrect argument");
			}
			const int subargs = lua_rawlen(l, -1);
			// Free any old restrictions if they are redefined
			for (std::vector<CBuildRestriction *>::iterator b = type->AiBuildingRules.begin();
				 b != type->AiBuildingRules.end(); ++b) {
				delete *b;
			}
			type->AiBuildingRules.clear();
			for (int k = 0; k < subargs; ++k) {
				lua_rawgeti(l, -1, k + 1);
				if (!lua_istable(l, -1)) {
					LuaError(l, "incorrect argument");
				}
				ParseBuildingRules(l, type->AiBuildingRules);
				lua_pop(l, 1);
			}
		} else if (!strcmp(value, "AutoBuildRate")) {
			type->AutoBuildRate = LuaToNumber(l, -1);
		} else if (!strcmp(value, "LandUnit")) {
			type->LandUnit = LuaToBoolean(l, -1);
		} else if (!strcmp(value, "AirUnit")) {
			type->AirUnit = LuaToBoolean(l, -1);
		} else if (!strcmp(value, "SeaUnit")) {
			type->SeaUnit = LuaToBoolean(l, -1);
		} else if (!strcmp(value, "RandomMovementProbability")) {
			type->RandomMovementProbability = LuaToNumber(l, -1);
		} else if (!strcmp(value, "RandomMovementDistance")) {
			type->RandomMovementDistance = LuaToNumber(l, -1);
		} else if (!strcmp(value, "ClicksToExplode")) {
			type->ClicksToExplode = LuaToNumber(l, -1);
		} else if (!strcmp(value, "CanTransport")) {
			//  Warning: CanTransport should only be used AFTER all bool flags
			//  have been defined.
			if (!lua_istable(l, -1)) {
				LuaError(l, "incorrect argument");
			}
			if (type->MaxOnBoard == 0) { // set default value.
				type->MaxOnBoard = 1;
			}

			if (type->BoolFlag.size() < UnitTypeVar.GetNumberBoolFlag()) {
				type->BoolFlag.resize(UnitTypeVar.GetNumberBoolFlag());
			}

			const int subargs = lua_rawlen(l, -1);
			for (int k = 0; k < subargs; ++k) {
				value = LuaToString(l, -1, k + 1);
				++k;

				const int index = UnitTypeVar.BoolFlagNameLookup[value];
				if (index != -1) {
					value = LuaToString(l, -1, k + 1);
					type->BoolFlag[index].CanTransport = Ccl2Condition(l, value);
					continue;
				}
				LuaError(l, "Unsupported flag tag for CanTransport: %s" _C_ value);
			}
		} else if (!strcmp(value, "CanGatherResources")) {
			const int args = lua_rawlen(l, -1);
			for (int j = 0; j < args; ++j) {
				lua_rawgeti(l, -1, j + 1);
				ResourceInfo *res = new ResourceInfo;
				if (!lua_istable(l, -1)) {
					LuaError(l, "incorrect argument");
				}
				const int subargs = lua_rawlen(l, -1);
				for (int k = 0; k < subargs; ++k) {
					value = LuaToString(l, -1, k + 1);
					++k;
					if (!strcmp(value, "resource-id")) {
						lua_rawgeti(l, -1, k + 1);
						res->ResourceId = CclGetResourceByName(l);
						lua_pop(l, 1);
						type->ResInfo[res->ResourceId] = res;
					} else if (!strcmp(value, "resource-step")) {
						res->ResourceStep = LuaToNumber(l, -1, k + 1);
					} else if (!strcmp(value, "final-resource")) {
						lua_rawgeti(l, -1, k + 1);
						res->FinalResource = CclGetResourceByName(l);
						lua_pop(l, 1);
					} else if (!strcmp(value, "wait-at-resource")) {
						res->WaitAtResource = LuaToNumber(l, -1, k + 1);
					} else if (!strcmp(value, "wait-at-depot")) {
						res->WaitAtDepot = LuaToNumber(l, -1, k + 1);
					} else if (!strcmp(value, "resource-capacity")) {
						res->ResourceCapacity = LuaToNumber(l, -1, k + 1);
					} else if (!strcmp(value, "terrain-harvester")) {
						res->TerrainHarvester = 1;
						--k;
					} else if (!strcmp(value, "lose-resources")) {
						res->LoseResources = 1;
						--k;
					} else if (!strcmp(value, "harvest-from-outside")) {
						res->HarvestFromOutside = 1;
						--k;
					} else if (!strcmp(value, "refinery-harvester")) {
						res->RefineryHarvester = 1;
						--k;
					} else if (!strcmp(value, "file-when-empty")) {
						res->FileWhenEmpty = LuaToString(l, -1, k + 1);
					} else if (!strcmp(value, "file-when-loaded")) {
						res->FileWhenLoaded = LuaToString(l, -1, k + 1);
					} else {
						printf("\n%s\n", type->Name.c_str());
						LuaError(l, "Unsupported tag: %s" _C_ value);
					}
				}
				if (!res->FinalResource) {
					res->FinalResource = res->ResourceId;
				}
				Assert(res->ResourceId);
				lua_pop(l, 1);
			}
			type->BoolFlag[HARVESTER_INDEX].value = 1;
		} else if (!strcmp(value, "GivesResource")) {
			lua_pushvalue(l, -1);
			type->GivesResource = CclGetResourceByName(l);
			lua_pop(l, 1);
		} else if (!strcmp(value, "CanStore")) {
			if (!lua_istable(l, -1)) {
				LuaError(l, "incorrect argument");
			}
			const int subargs = lua_rawlen(l, -1);
			for (int k = 0; k < subargs; ++k) {
				lua_rawgeti(l, -1, k + 1);
				type->CanStore[CclGetResourceByName(l)] = 1;
				lua_pop(l, 1);
			}
		} else if (!strcmp(value, "CanCastSpell")) {
			if (!lua_istable(l, -1)) {
				LuaError(l, "incorrect argument");
			}
			//
			// Warning: can-cast-spell should only be used AFTER all spells
			// have been defined. FIXME: MaxSpellType=500 or something?
			//
			if (!type->CanCastSpell) {
				type->CanCastSpell = new char[SpellTypeTable.size()];
				memset(type->CanCastSpell, 0, SpellTypeTable.size() * sizeof(char));
			}
			const int subargs = lua_rawlen(l, -1);
			if (subargs == 0) {
				delete[] type->CanCastSpell;
				type->CanCastSpell = NULL;
			}
			for (int k = 0; k < subargs; ++k) {
				value = LuaToString(l, -1, k + 1);
				const SpellType *spell = SpellTypeByIdent(value);
				if (spell == NULL) {
					LuaError(l, "Unknown spell type: %s" _C_ value);
				}
				type->CanCastSpell[spell->Slot] = 1;
			}
		} else if (!strcmp(value, "AutoCastActive")) {
			if (!lua_istable(l, -1)) {
				LuaError(l, "incorrect argument");
			}
			//
			// Warning: AutoCastActive should only be used AFTER all spells
			// have been defined.
			//
			if (!type->AutoCastActive) {
				type->AutoCastActive = new char[SpellTypeTable.size()];
				memset(type->AutoCastActive, 0, SpellTypeTable.size() * sizeof(char));
			}
			const int subargs = lua_rawlen(l, -1);
			if (subargs == 0) {
				delete[] type->AutoCastActive;
				type->AutoCastActive = NULL;

			}
			for (int k = 0; k < subargs; ++k) {
				value = LuaToString(l, -1, k + 1);
				const SpellType *spell = SpellTypeByIdent(value);
				if (spell == NULL) {
					LuaError(l, "AutoCastActive : Unknown spell type: %s" _C_ value);
				}
				if (!spell->AutoCast) {
					LuaError(l, "AutoCastActive : Define autocast method for %s." _C_ value);
				}
				type->AutoCastActive[spell->Slot] = 1;
			}
		} else if (!strcmp(value, "CanTargetFlag")) {
			//
			// Warning: can-target-flag should only be used AFTER all bool flags
			// have been defined.
			//
			if (!lua_istable(l, -1)) {
				LuaError(l, "incorrect argument");
			}
			if (type->BoolFlag.size() < UnitTypeVar.GetNumberBoolFlag()) {
				type->BoolFlag.resize(UnitTypeVar.GetNumberBoolFlag());
			}
			const int subargs = lua_rawlen(l, -1);
			for (int k = 0; k < subargs; ++k) {
				value = LuaToString(l, -1, k + 1);
				++k;
				int index = UnitTypeVar.BoolFlagNameLookup[value];
				if (index != -1) {
					value = LuaToString(l, -1, k + 1);
					type->BoolFlag[index].CanTargetFlag = Ccl2Condition(l, value);
					continue;
				}
				LuaError(l, "Unsupported flag tag for can-target-flag: %s" _C_ value);
			}
		} else if (!strcmp(value, "PriorityTarget")) {
			//
			// Warning: ai-priority-target should only be used AFTER all bool flags
			// have been defined.
			//
			if (!lua_istable(l, -1)) {
				LuaError(l, "incorrect argument");
			}
			if (type->BoolFlag.size() < UnitTypeVar.GetNumberBoolFlag()) {
				type->BoolFlag.resize(UnitTypeVar.GetNumberBoolFlag());
			}
			const int subargs = lua_rawlen(l, -1);
			for (int k = 0; k < subargs; ++k) {
				value = LuaToString(l, -1, k + 1);
				++k;
				int index = UnitTypeVar.BoolFlagNameLookup[value];
				if (index != -1) {
					value = LuaToString(l, -1, k + 1);
					type->BoolFlag[index].AiPriorityTarget = Ccl2Condition(l, value);
					continue;
				}
				LuaError(l, "Unsupported flag tag for ai-priority-target: %s" _C_ value);
			}
		} else if (!strcmp(value, "Sounds")) {
			if (!lua_istable(l, -1)) {
				LuaError(l, "incorrect argument");
			}
			const int subargs = lua_rawlen(l, -1);
			for (int k = 0; k < subargs; ++k) {
				value = LuaToString(l, -1, k + 1);
				++k;

				if (!strcmp(value, "selected")) {
					type->Sound.Selected.Name = LuaToString(l, -1, k + 1);
				} else if (!strcmp(value, "acknowledge")) {
					type->Sound.Acknowledgement.Name = LuaToString(l, -1, k + 1);
				} else if (!strcmp(value, "attack")) {
					type->Sound.Attack.Name = LuaToString(l, -1, k + 1);
				} else if (!strcmp(value, "build")) {
					type->Sound.Build.Name = LuaToString(l, -1, k + 1);
				} else if (!strcmp(value, "ready")) {
					type->Sound.Ready.Name = LuaToString(l, -1, k + 1);
				} else if (!strcmp(value, "repair")) {
					type->Sound.Repair.Name = LuaToString(l, -1, k + 1);
				} else if (!strcmp(value, "harvest")) {
					const std::string name = LuaToString(l, -1, k + 1);
					++k;
					const int resId = GetResourceIdByName(l, name.c_str());
					type->Sound.Harvest[resId].Name = LuaToString(l, -1, k + 1);
				} else if (!strcmp(value, "help")) {
					type->Sound.Help.Name = LuaToString(l, -1, k + 1);
				} else if (!strcmp(value, "work-complete")) {
					type->Sound.WorkComplete.Name = LuaToString(l, -1, k + 1);
				} else if (!strcmp(value, "dead")) {
					int death;

					const std::string name = LuaToString(l, -1, k + 1);
					for (death = 0; death < ANIMATIONS_DEATHTYPES; ++death) {
						if (name == ExtraDeathTypes[death]) {
							++k;
							break;
						}
					}
					if (death == ANIMATIONS_DEATHTYPES) {
						type->Sound.Dead[ANIMATIONS_DEATHTYPES].Name = name;
					} else {
						type->Sound.Dead[death].Name = LuaToString(l, -1, k + 1);
					}
				} else {
					LuaError(l, "Unsupported sound tag: %s" _C_ value);
				}
			}
		} else {
			int index = UnitTypeVar.VariableNameLookup[value];
			if (index != -1) { // valid index
				if (lua_isboolean(l, -1)) {
					type->DefaultStat.Variables[index].Enable = LuaToBoolean(l, -1);
				} else if (lua_istable(l, -1)) {
					DefineVariableField(l, type->DefaultStat.Variables + index, -1);
				} else if (lua_isnumber(l, -1)) {
					type->DefaultStat.Variables[index].Enable = 1;
					type->DefaultStat.Variables[index].Value = LuaToNumber(l, -1);
					type->DefaultStat.Variables[index].Max = LuaToNumber(l, -1);
				} else { // Error
					LuaError(l, "incorrect argument for the variable in unittype");
				}
				continue;
			}

			if (type->BoolFlag.size() < UnitTypeVar.GetNumberBoolFlag()) {
				type->BoolFlag.resize(UnitTypeVar.GetNumberBoolFlag());
			}

			index = UnitTypeVar.BoolFlagNameLookup[value];
			if (index != -1) {
				if (lua_isnumber(l, -1)) {
					type->BoolFlag[index].value = LuaToNumber(l, -1);
				} else {
					type->BoolFlag[index].value = LuaToBoolean(l, -1);
				}
			} else {
				printf("\n%s\n", type->Name.c_str());
				LuaError(l, "Unsupported tag: %s" _C_ value);
			}
		}
	}

	// If number of directions is not specified, make a guess
	// Building have 1 direction and units 8
	if (type->Building && type->NumDirections == 0) {
		type->NumDirections = 1;
	} else if (type->NumDirections == 0) {
		type->NumDirections = 8;
	}

	// FIXME: try to simplify/combine the flags instead
	if (type->MouseAction == MouseActionAttack && !type->CanAttack) {
		LuaError(l, "Unit-type '%s': right-attack is set, but can-attack is not\n" _C_ type->Name.c_str());
	}
	UpdateDefaultBoolFlags(*type);
	if (!CclInConfigFile) {
		if (redefine & redefineSprite) {
			LoadUnitTypeSprite(*type);
		}
		UpdateUnitStats(*type, 1);
	}
	return 0;
}

CopyUnitType


Description

Copy a unit type.

@param l Lua state.

Example:

CopyUnitType("unit-peasant", "unit-peasant-copy")

/unit/script_unittype.cpp:1444 CclCopyUnitType

static int CclCopyUnitType(lua_State *l)
{
	LuaCheckArgs(l, 2);

	// Slot identifier
	const char* fromName = LuaToString(l, 1);
	CUnitType *from = UnitTypeByIdent(fromName);
	const char* toName = LuaToString(l, 2);
	CUnitType *to = UnitTypeByIdent(toName);
	if (to) {
		DebugPrint("Redefining unit-type '%s'\n" _C_ toName);
	} else {
		to = NewUnitTypeSlot(toName);
	}
	if (!from) {
		LuaError(l, "Unknown unit-type '%s'\n" _C_ fromName);
	}

	to->Flip = from->Flip;
	to->Name = toName;
	to->File = from->File;
	to->AltFile = from->AltFile;
	to->Width = from->Width;
	to->Height = from->Height;
	if (to->Sprite) {
		CGraphic::Free(to->Sprite);
		to->Sprite = NULL;
	}
	if (to->AltSprite) {
		CGraphic::Free(to->AltSprite);
		to->AltSprite = NULL;
	}
	to->ShadowFile = from->ShadowFile;
	to->ShadowWidth = from->ShadowWidth;
	to->ShadowHeight = from->ShadowHeight;
	to->ShadowOffsetX = from->ShadowOffsetX;
	to->ShadowOffsetY = from->ShadowOffsetY;
	to->ShadowSpriteFrame = from->ShadowSpriteFrame;
	to->ShadowScale = from->ShadowScale;
	if (to->ShadowSprite) {
		CGraphic::Free(to->ShadowSprite);
		to->ShadowSprite = NULL;
	}
	to->OffsetX = from->OffsetX;
	to->OffsetY = from->OffsetY;
	to->Animations = from->Animations;
	to->Icon.Name = from->Icon.Name;
	to->Icon.Icon = NULL;
#ifdef USE_MNG
	to->Portrait.Num = from->Portrait.Num;
	to->Portrait.Talking = from->Portrait.Talking;
	to->Portrait.Files = new std::string[to->Portrait.Num];
	for (int i = 0; i < to->Portrait.Num; i++) {
		to->Portrait.Files[i] = from->Portrait.Files[i];
	}
	to->Portrait.Mngs = new Mng *[to->Portrait.Num];
	memset(to->Portrait.Mngs, 0, to->Portrait.Num * sizeof(Mng *));
#endif
	memcpy(to->DefaultStat.Costs, from->DefaultStat.Costs, sizeof(from->DefaultStat.Costs));
	memcpy(to->DefaultStat.Storing, from->DefaultStat.Storing, sizeof(from->DefaultStat.Storing));
	memcpy(to->DefaultStat.ImproveIncomes, from->DefaultStat.ImproveIncomes, sizeof(from->DefaultStat.ImproveIncomes));
	to->Construction = from->Construction;
	to->DrawLevel = from->DrawLevel;
	to->MaxOnBoard = from->MaxOnBoard;
	to->BoardSize = from->BoardSize;
	to->ButtonLevelForTransporter = from->ButtonLevelForTransporter;
	to->StartingResources = from->StartingResources;
	to->DefaultStat.Variables[HP_INDEX].Increase = from->DefaultStat.Variables[HP_INDEX].Increase;
	to->DefaultStat.Variables[HP_INDEX].IncreaseFrequency = from->DefaultStat.Variables[HP_INDEX].IncreaseFrequency;
	to->BurnPercent = from->BurnPercent;
	to->BurnDamageRate = from->BurnDamageRate;
	to->PoisonDrain = from->PoisonDrain;
	to->DefaultStat.Variables[SHIELD_INDEX].Max = from->DefaultStat.Variables[SHIELD_INDEX].Max;
	to->DefaultStat.Variables[SHIELD_INDEX].Value = from->DefaultStat.Variables[SHIELD_INDEX].Value;
	to->DefaultStat.Variables[SHIELD_INDEX].Increase = from->DefaultStat.Variables[SHIELD_INDEX].Increase;
	to->DefaultStat.Variables[SHIELD_INDEX].Enable = from->DefaultStat.Variables[SHIELD_INDEX].Enable;
	to->TileWidth = from->TileWidth;
	to->TileHeight = from->TileHeight;
	to->NeutralMinimapColorRGB = from->NeutralMinimapColorRGB;
	to->Neutral = from->Neutral;
	to->BoxWidth = from->BoxWidth;
	to->BoxHeight = from->BoxHeight;
	to->BoxOffsetX = from->BoxOffsetX;
	to->BoxOffsetY = from->BoxOffsetY;
	to->NumDirections = from->NumDirections;
	to->ReactRangeComputer = from->ReactRangeComputer;
	to->ReactRangePerson = from->ReactRangePerson;
	to->Missile.Name = from->Missile.Name;
	to->Missile.Missile = NULL; // filled in later
	to->MinAttackRange = from->MinAttackRange;
	to->DefaultStat.Variables[ATTACKRANGE_INDEX].Value = from->DefaultStat.Variables[ATTACKRANGE_INDEX].Value;
	to->DefaultStat.Variables[ATTACKRANGE_INDEX].Max = from->DefaultStat.Variables[ATTACKRANGE_INDEX].Max;
	to->DefaultStat.Variables[ATTACKRANGE_INDEX].Enable = from->DefaultStat.Variables[ATTACKRANGE_INDEX].Enable;
	to->DefaultStat.Variables[MAXHARVESTERS_INDEX].Value = from->DefaultStat.Variables[MAXHARVESTERS_INDEX].Value;
	to->DefaultStat.Variables[MAXHARVESTERS_INDEX].Max = from->DefaultStat.Variables[MAXHARVESTERS_INDEX].Max;
	to->DefaultStat.Variables[PRIORITY_INDEX].Value = from->DefaultStat.Variables[PRIORITY_INDEX].Value;
	to->DefaultStat.Variables[PRIORITY_INDEX].Max = from->DefaultStat.Variables[PRIORITY_INDEX].Max;
	to->AnnoyComputerFactor = from->AnnoyComputerFactor;
	to->AiAdjacentRange = from->AiAdjacentRange;
	to->DecayRate = from->DecayRate;
	to->CorpseName = from->CorpseName;
	to->CorpseType = from->CorpseType;
	to->DamageType = from->DamageType;
	to->ExplodeWhenKilled = from->ExplodeWhenKilled;
	to->Explosion.Name = from->Explosion.Name;
	to->Explosion.Missile = NULL; // filled later
	to->TeleportCost = from->TeleportCost;
	to->TeleportEffectIn = from->TeleportEffectIn;
	to->TeleportEffectOut = from->TeleportEffectOut;
	to->OnDeath = from->OnDeath;
	to->OnHit = from->OnHit;
	to->OnEachCycle = from->OnEachCycle;
	to->OnEachSecond = from->OnEachSecond;
	to->OnInit = from->OnInit;
	to->OnReady = from->OnReady;
	to->UnitType = from->UnitType;
	for (int k = 0; k < MaxAttackPos; ++k) {
		for (int m = 0; m < UnitSides; ++m) {
			to->MissileOffsets[m][k].x = from->MissileOffsets[m][k].x;
			to->MissileOffsets[m][k].y = from->MissileOffsets[m][k].y;
		}
	}
	for (int i = 0; i < ANIMATIONS_DEATHTYPES + 2; i++) {
		to->Impact[i].Name = from->Impact[i].Name;
		to->Impact[i].Missile = from->Impact[i].Missile;
	}
	to->MouseAction = from->MouseAction;
	to->CanAttack = from->CanAttack;
	to->RepairRange = from->RepairRange;
	to->RepairHP = from->RepairHP;
	memcpy(to->RepairCosts, from->RepairCosts, sizeof(from->RepairCosts));
	to->CanTarget = from->CanTarget;
	to->Building = from->Building;
	to->BuildingRules.clear();
	if (!from->BuildingRules.empty()) {
		printf("WARNING: unit type copy %s of %s does not inherit BuildingRules\n", fromName, toName);
	}
	// XXX: should copy, not share, this will crash
	// for (auto rule : from->BuildingRules) {
	// 	to->BuildingRules.push_back(rule);
	// }
	to->AiBuildingRules.clear();
	if (!from->AiBuildingRules.empty()) {
		printf("WARNING: unit type copy %s of %s does not inherit AiBuildingRules\n", fromName, toName);
	}
	// XXX: should copy, not share, this would crash
	// for (auto rule : from->AiBuildingRules) {
	// 	to->AiBuildingRules.push_back(rule);
	// }
	to->AutoBuildRate = from->AutoBuildRate;
	to->LandUnit = from->LandUnit;
	to->AirUnit = from->AirUnit;
	to->SeaUnit = from->SeaUnit;
	to->RandomMovementProbability = from->RandomMovementProbability;
	to->RandomMovementDistance = from->RandomMovementDistance;
	to->ClicksToExplode = from->ClicksToExplode;
	to->MaxOnBoard = from->MaxOnBoard;
	for (unsigned int i = 0; i < from->BoolFlag.size(); i++) {
		to->BoolFlag[i].value = from->BoolFlag[i].value;
		to->BoolFlag[i].CanTransport = from->BoolFlag[i].CanTransport;
		to->BoolFlag[i].CanTargetFlag = from->BoolFlag[i].CanTargetFlag;
		to->BoolFlag[i].AiPriorityTarget = from->BoolFlag[i].AiPriorityTarget;
	}
	memcpy(to->ResInfo, from->ResInfo, sizeof(from->ResInfo));
	to->GivesResource = from->GivesResource;
	memcpy(to->CanStore, from->CanStore, sizeof(from->CanStore));
	to->CanCastSpell = from->CanCastSpell;
	to->AutoCastActive = from->AutoCastActive;
	to->Sound.Selected.Name = from->Sound.Selected.Name;
	to->Sound.Acknowledgement.Name = from->Sound.Acknowledgement.Name;
	to->Sound.Attack.Name = from->Sound.Attack.Name;
	to->Sound.Build.Name = from->Sound.Build.Name;
	to->Sound.Ready.Name = from->Sound.Ready.Name;
	to->Sound.Repair.Name = from->Sound.Repair.Name;
	for (int i = 0; i < MaxCosts; i++) {
		to->Sound.Harvest[i].Name = from->Sound.Harvest[i].Name;
	}
	to->Sound.Help.Name = from->Sound.Help.Name;
	to->Sound.WorkComplete.Name = from->Sound.WorkComplete.Name;
	for (unsigned int i = 0; i < ANIMATIONS_DEATHTYPES + 1; i++) {
		to->Sound.Dead[i].Name = from->Sound.Dead[i].Name;
	}
	for (unsigned int i = 0; i < UnitTypeVar.GetNumberVariable(); i++) {
		to->DefaultStat.Variables[i].Enable = from->DefaultStat.Variables[i].Enable;
		to->DefaultStat.Variables[i].Value = from->DefaultStat.Variables[i].Value;
		to->DefaultStat.Variables[i].Max = from->DefaultStat.Variables[i].Max;
		to->DefaultStat.Variables[i].Increase = from->DefaultStat.Variables[i].Increase;
		to->DefaultStat.Variables[i].IncreaseFrequency = from->DefaultStat.Variables[i].IncreaseFrequency;
	}

	UpdateDefaultBoolFlags(*to);
	if (!CclInConfigFile) {
		UpdateUnitStats(*to, 1);
	}
	LoadUnitTypes();
	return 0;
}

DefineUnitStats


Description

Parse unit-stats.

@param l Lua state.

Example:

DefineUnitStats("unit-berserker", 2, {
"HitPoints", {Value = 55, Max = 55, Increase = 0, Enable = true},
"AttackRange", {Value = 5, Max = 6, Increase = 0, Enable = true},
"SightRange", {Value = 7, Max = 7, Increase = 0, Enable = true},
})

/unit/script_unittype.cpp:1545 CclDefineUnitStats

static int CclDefineUnitStats(lua_State *l)
{
	CUnitType *type = UnitTypeByIdent(LuaToString(l, 1));
	const int playerId = LuaToNumber(l, 2);

	Assert(type);
	Assert(playerId < PlayerMax);

	CUnitStats *stats = &type->Stats[playerId];
	if (!stats->Variables) {
		stats->Variables = new CVariable[UnitTypeVar.GetNumberVariable()];
	}

	// Parse the list: (still everything could be changed!)
	const int args = lua_rawlen(l, 3);
	for (int j = 0; j < args; ++j) {
		const char *value = LuaToString(l, 3, j + 1);
		++j;

		if (!strcmp(value, "costs")) {
			lua_rawgeti(l, 3, j + 1);
			if (!lua_istable(l, -1)) {
				LuaError(l, "incorrect argument");
			}
			const int subargs = lua_rawlen(l, -1);

			for (int k = 0; k < subargs; ++k) {
				lua_rawgeti(l, 3, j + 1);
				value = LuaToString(l, -1, k + 1);
				++k;
				const int resId = GetResourceIdByName(l, value);
				stats->Costs[resId] = LuaToNumber(l, -1, k + 1);
				lua_pop(l, 1);
			}
		} else if (!strcmp(value, "storing")) {
			lua_rawgeti(l, 3, j + 1);
			if (!lua_istable(l, -1)) {
				LuaError(l, "incorrect argument");
			}
			const int subargs = lua_rawlen(l, -1);

			for (int k = 0; k < subargs; ++k) {
				lua_rawgeti(l, 3, j + 1);
				value = LuaToString(l, -1, k + 1);
				++k;
				const int resId = GetResourceIdByName(l, value);
				stats->Storing[resId] = LuaToNumber(l, -1, k + 1);
				lua_pop(l, 1);
			}
		} else if (!strcmp(value, "improve-production")) {
			lua_rawgeti(l, 3, j + 1);
			if (!lua_istable(l, -1)) {
				LuaError(l, "incorrect argument");
			}
			const int subargs = lua_rawlen(l, -1);

			for (int k = 0; k < subargs; ++k) {
				lua_rawgeti(l, 3, j + 1);
				value = LuaToString(l, -1, k + 1);
				++k;
				const int resId = GetResourceIdByName(l, value);
				stats->ImproveIncomes[resId] = LuaToNumber(l, -1, k + 1);
				lua_pop(l, 1);
			}
		} else {
			int i = UnitTypeVar.VariableNameLookup[value];// User variables
			if (i != -1) { // valid index
				lua_rawgeti(l, 3, j + 1);
				if (lua_istable(l, -1)) {
					DefineVariableField(l, stats->Variables + i, -1);
				} else if (lua_isnumber(l, -1)) {
					stats->Variables[i].Enable = 1;
					stats->Variables[i].Value = LuaToNumber(l, -1);
					stats->Variables[i].Max = LuaToNumber(l, -1);
				} else { // Error
					LuaError(l, "incorrect argument for the variable in unittype");
				}
				continue;
			}
			// This leaves a half initialized unit
			LuaError(l, "Unsupported tag: %s" _C_ value);
		}
	}
	return 0;
}

DefineBoolFlags


Define boolean flag.

@param l Lua state.

/unit/script_unittype.cpp:1997 CclDefineBoolFlags

static int CclDefineBoolFlags(lua_State *l)
{
	const unsigned int old = UnitTypeVar.GetNumberBoolFlag();
	const int args = lua_gettop(l);
	for (int j = 0; j < args; ++j) {
		const char *str = LuaToString(l, j + 1);

		UnitTypeVar.BoolFlagNameLookup.AddKey(str);

	}

	if (0 < old && old != UnitTypeVar.GetNumberBoolFlag()) {
		size_t new_size = UnitTypeVar.GetNumberBoolFlag();
		for (std::vector<CUnitType *>::size_type i = 0; i < UnitTypes.size(); ++i) { // adjust array for unit already defined
			UnitTypes[i]->BoolFlag.resize(new_size);
		}
	}
	return 0;
}

DefineVariables


Define user variables.

@param l Lua state.

/unit/script_unittype.cpp:1972 CclDefineVariables

static int CclDefineVariables(lua_State *l)
{
	int old = UnitTypeVar.GetNumberVariable();

	const int args = lua_gettop(l);
	for (int j = 0; j < args; ++j) {
		const char *str = LuaToString(l, j + 1);

		const int index = UnitTypeVar.VariableNameLookup.AddKey(str);
		if (index == old) {
			old++;
			UnitTypeVar.Variable.resize(old);
		} else {
			DebugPrint("Warning, User Variable \"%s\" redefined\n" _C_ str);
		}
		if (!lua_istable(l, j + 2)) { // No change => default value.
			continue;
		}
		++j;
		DefineVariableField(l, &(UnitTypeVar.Variable[index]), j + 1);
	}
	return 0;
}

DefineDecorations


Define Decorations for user variables

@param l Lua state.

@todo modify Assert with luastate with User Error.
@todo continue to add configuration.

/unit/script_unittype.cpp:2202 CclDefineDecorations

static int CclDefineDecorations(lua_State *l)
{
	struct {
		int Index;
		int OffsetX;
		int OffsetY;
		int OffsetXPercent;
		int OffsetYPercent;
		bool IsCenteredInX;
		bool IsCenteredInY;
		bool ShowIfNotEnable;
		bool ShowWhenNull;
		bool HideHalf;
		bool ShowWhenMax;
		bool ShowOnlySelected;
		bool HideNeutral;
		bool HideAllied;
		bool ShowOpponent;
		bool BoolFlagInvert;
		int BoolFlag;
	} tmp;

	const int nargs = lua_gettop(l);
	for (int i = 0; i < nargs; i++) {
		Assert(lua_istable(l, i + 1));
		CDecoVar *decovar = NULL;
		memset(&tmp, 0, sizeof(tmp));
		lua_pushnil(l);
		while (lua_next(l, i + 1)) {
			const char *key = LuaToString(l, -2);
			if (!strcmp(key, "Index")) {
				const char *const value = LuaToString(l, -1);
				tmp.Index = UnitTypeVar.VariableNameLookup[value];// User variables
				Assert(tmp.Index != -1);
			} else if (!strcmp(key, "Offset")) {
				CclGetPos(l, &tmp.OffsetX, &tmp.OffsetY);
			} else if (!strcmp(key, "OffsetPercent")) {
				CclGetPos(l, &tmp.OffsetXPercent, &tmp.OffsetYPercent);
			} else if (!strcmp(key, "CenterX")) {
				tmp.IsCenteredInX = LuaToBoolean(l, -1);
			} else if (!strcmp(key, "CenterY")) {
				tmp.IsCenteredInY = LuaToBoolean(l, -1);
			} else if (!strcmp(key, "ShowIfNotEnable")) {
				tmp.ShowIfNotEnable = LuaToBoolean(l, -1);
			} else if (!strcmp(key, "ShowWhenNull")) {
				tmp.ShowWhenNull = LuaToBoolean(l, -1);
			} else if (!strcmp(key, "HideHalf")) {
				tmp.HideHalf = LuaToBoolean(l, -1);
			} else if (!strcmp(key, "ShowWhenMax")) {
				tmp.ShowWhenMax = LuaToBoolean(l, -1);
			} else if (!strcmp(key, "ShowOnlySelected")) {
				tmp.ShowOnlySelected = LuaToBoolean(l, -1);
			} else if (!strcmp(key, "HideNeutral")) {
				tmp.HideNeutral = LuaToBoolean(l, -1);
			} else if (!strcmp(key, "HideAllied")) {
				tmp.HideAllied = LuaToBoolean(l, -1);
			} else if (!strcmp(key, "ShowOpponent")) {
				tmp.ShowOpponent = LuaToBoolean(l, -1);
			} else if (!strcmp(key, "Method")) {
				Assert(lua_istable(l, -1));
				lua_rawgeti(l, -1, 1); // MethodName
				lua_rawgeti(l, -2, 2); // Data
				Assert(lua_istable(l, -1));
				key = LuaToString(l, -2);
				if (!strcmp(key, "bar")) {
					CDecoVarBar *decovarbar = new CDecoVarBar;
					lua_pushnil(l);
					while (lua_next(l, -2)) {
						key = LuaToString(l, -2);
						if (!strcmp(key, "Height")) {
							decovarbar->Height = LuaToNumber(l, -1);
						} else if (!strcmp(key, "Width")) {
							decovarbar->Width = LuaToNumber(l, -1);
						} else if (!strcmp(key, "MinValue")) {
							decovarbar->MinValue = LuaToNumber(l, -1);
						} else if (!strcmp(key, "MaxValue")) {
							decovarbar->MaxValue = LuaToNumber(l, -1);
						} else if (!strcmp(key, "Invert")) {
							decovarbar->Invert = LuaToBoolean(l, -1);
						} else if (!strcmp(key, "Orientation")) {
							key = LuaToString(l, -1);
							if (!strcmp(key, "horizontal")) {
								decovarbar->IsVertical = 0;
							} else if (!strcmp(key, "vertical")) {
								decovarbar->IsVertical = 1;
							} else { // Error
								LuaError(l, "invalid Orientation '%s' for bar in DefineDecorations" _C_ key);
							}
						} else if (!strcmp(key, "SEToNW")) {
							decovarbar->SEToNW = LuaToBoolean(l, -1);
						} else if (!strcmp(key, "BorderSize")) {
							decovarbar->BorderSize = LuaToNumber(l, -1);
						} else if (!strcmp(key, "ShowFullBackground")) {
							decovarbar->ShowFullBackground = LuaToBoolean(l, -1);
#if 0 // FIXME Color configuration
						} else if (!strcmp(key, "Color")) {
							decovar->Color = // FIXME
						} else if (!strcmp(key, "BColor")) {
							decovar->BColor = // FIXME
#endif
						} else {
							LuaError(l, "'%s' invalid for Method bar" _C_ key);
						}
						lua_pop(l, 1); // Pop value
					}
					decovar = decovarbar;
				} else if (!strcmp(key, "frame")) {
					CDecoVarFrame *frame = new CDecoVarFrame;
					if (!lua_istable(l, -1)) {
						LuaError(l, "incorrect argument, need table with Thickness= and Color=");
					}
					for (lua_pushnil(l); lua_next(l, -2); lua_pop(l, 1)) {
						const char* innerkey = LuaToString(l, -2);
						if (!strcmp(innerkey, "Thickness")) {
							frame->Thickness = LuaToNumber(l, -1);
						} else if (!strcmp(innerkey, "ColorName")) {
							const char *const colorName = LuaToString(l, -1);
							frame->ColorIndex = GetColorIndexByName(colorName);
						} else {
							LuaError(l, "'%s' invalid for Method frame" _C_ innerkey);
						}
					}
					decovar = frame;
				} else if (!strcmp(key, "text")) {
					CDecoVarText *decovartext = new CDecoVarText;

					decovartext->Font = CFont::Get(LuaToString(l, -1, 1));
					// FIXME : More arguments ? color...
					decovar = decovartext;
				} else if (!strcmp(key, "sprite")) {
					CDecoVarSpriteBar *decovarspritebar = new CDecoVarSpriteBar;
					decovarspritebar->NSprite = GetSpriteIndex(LuaToString(l, -1, 1));
					if (decovarspritebar->NSprite == -1) {
						LuaError(l, "invalid sprite-name '%s' for Method in DefineDecorations" _C_ LuaToString(l, -1, 1));
					}
					// FIXME : More arguments ?
					decovar = decovarspritebar;
				} else if (!strcmp(key, "static-sprite")) {
					CDecoVarStaticSprite *decovarstaticsprite = new CDecoVarStaticSprite;
					if (lua_rawlen(l, -1) == 2) {
						decovarstaticsprite->NSprite = GetSpriteIndex(LuaToString(l, -1, 1));
						decovarstaticsprite->n = LuaToNumber(l, -1, 2);
					} else {
						decovarstaticsprite->NSprite = GetSpriteIndex(LuaToString(l, -1, 1));
						decovarstaticsprite->n = LuaToNumber(l, -1, 2);
						decovarstaticsprite->FadeValue = LuaToNumber(l, -1, 3);
					}
					decovar = decovarstaticsprite;
				} else if (!strcmp(key, "animated-sprite")) {
					CDecoVarAnimatedSprite *decovarspritebar = new CDecoVarAnimatedSprite;
					decovarspritebar->NSprite = GetSpriteIndex(LuaToString(l, -1, 1));
					if (decovarspritebar->NSprite == -1) {
						LuaError(l, "invalid sprite-name '%s' for Method in DefineDecorations" _C_ LuaToString(l, -1, 1));
					}
					decovarspritebar->WaitFrames = LuaToNumber(l, -1, 2);
					if (decovarspritebar->WaitFrames <= 0) {
						LuaError(l, "invalid wait-frames, must be > 0");
					}
					decovar = decovarspritebar;
				} else { // Error
					LuaError(l, "invalid method '%s' for Method in DefineDecorations" _C_ key);
				}
				lua_pop(l, 2); // MethodName and data
			} else {
				tmp.BoolFlag = UnitTypeVar.BoolFlagNameLookup[key];
				if (tmp.BoolFlag != -1) {
					tmp.BoolFlagInvert = LuaToBoolean(l, -1);
				} else {
					// Error
					LuaError(l, "invalid key '%s' for DefineDecorations" _C_ key);
				}
			}
			lua_pop(l, 1); // Pop the value
		}
		decovar->Index = tmp.Index;
		decovar->OffsetX = tmp.OffsetX;
		decovar->OffsetY = tmp.OffsetY;
		decovar->OffsetXPercent = tmp.OffsetXPercent;
		decovar->OffsetYPercent = tmp.OffsetYPercent;
		decovar->IsCenteredInX = tmp.IsCenteredInX;
		decovar->IsCenteredInY = tmp.IsCenteredInY;
		decovar->ShowIfNotEnable = tmp.ShowIfNotEnable;
		decovar->ShowWhenNull = tmp.ShowWhenNull;
		decovar->HideHalf = tmp.HideHalf;
		decovar->ShowWhenMax = tmp.ShowWhenMax;
		decovar->ShowOnlySelected = tmp.ShowOnlySelected;
		decovar->HideNeutral = tmp.HideNeutral;
		decovar->HideAllied = tmp.HideAllied;
		decovar->ShowOpponent = tmp.ShowOpponent;
		decovar->BoolFlag = tmp.BoolFlag;
		decovar->BoolFlagInvert = tmp.BoolFlagInvert;
		UnitTypeVar.DecoVar.push_back(decovar);
	}
	Assert(lua_gettop(l));
	return 0;
}

DefinePaletteSwap

/unit/script_unittype.cpp:2297 CclDefinePaletteSwap

static int CclDefinePaletteSwap(lua_State *l)
{
	LuaCheckArgs(l, 2);
	const char *iconName = LuaToString(l, 1);
	CIcon *icon = CIcon::Get(iconName);
	if (!icon) {
		LuaError(l, "icon %s not found" _C_ iconName);
	}

	if (!lua_istable(l, 2)) {
		LuaError(l, "incorrect argument");
	}
	const int subargs = lua_rawlen(l, 2);
	std::vector<PaletteSwap> newSwaps;
	for (int k = 0; k < subargs; k += 2) {
		const char *value = LuaToString(l, 2, k + 1);
		int index = UnitTypeVar.VariableNameLookup[value];
		if (index == -1) {
			LuaError(l, "unknown variable name %s" _C_ value);
		}

		lua_rawgeti(l, 2, k + 2); // swap table
		if (!lua_istable(l, -1) || lua_rawlen(l, -1) != 2) {
			LuaError(l, "incorrect argument, need length 2 table with {startColorIndex, { ... color steps ... }");
		}
		int startColorIndex = LuaToNumber(l, -1, 1);

		lua_rawgeti(l, -1, 2); // swap table, steps table
		if (!lua_istable(l, -1)) {
			LuaError(l, "incorrect argument, need table with color steps");
		}

		int steps = lua_rawlen(l, -1);
		std::vector<CColor> colors;
		int colorCount = 0;
		int alternativesCount = 0;
		for (int step = 0; step < steps; step++) {
			lua_rawgeti(l, -1, step + 1); // swap table, steps table, alternatives table
			if (alternativesCount) {
				if (lua_rawlen(l, -1) != alternativesCount) {
					LuaError(l, "incorrect argument, need table with %d alternatives, got %zu" _C_ alternativesCount _C_ lua_rawlen(l, -1));
				}
			} else {
				alternativesCount = lua_rawlen(l, -1);
			}
			for (int alt = 0; alt < alternativesCount; alt++) {
				lua_rawgeti(l, -1, alt + 1); // swap table, steps table, alternatives table, color table
				if (!lua_istable(l, -1)) {
					LuaError(l, "incorrect argument, need table with colors");
				}
				if (colorCount) {
					if (lua_rawlen(l, -1) != colorCount) {
						LuaError(l, "incorrect argument, need table with %d colors, got %zu" _C_ colorCount _C_ lua_rawlen(l, -1));
					}
				} else {
					colorCount = lua_rawlen(l, -1);
				}
				for (int color = 0; color < colorCount; color++) {
					lua_rawgeti(l, -1, color + 1);
					CColor c;
					c.Parse(l);
					colors.push_back(c);
					lua_pop(l, 1);
				}
				lua_pop(l, 1); // swap table, steps table, alternatives table
			}
			lua_pop(l, 1);  // swap table, steps table
		}
		lua_pop(l, 1); // swap table
		lua_pop(l, 1); // <emtpy>
		newSwaps.emplace_back(index, startColorIndex, colorCount, steps, alternativesCount, colors);
	}
	icon->SetPaletteSwaps(newSwaps);
	return 0;
}

DefineExtraDeathTypes


Define default extra death types.

@param l Lua state.

/unit/script_unittype.cpp:2221 CclDefineExtraDeathTypes

static int CclDefineExtraDeathTypes(lua_State *l)
{
	unsigned int args;

	for (unsigned int i = 0; i < ANIMATIONS_DEATHTYPES; ++i) {
		ExtraDeathTypes[i].clear();
	}
	args = lua_gettop(l);
	for (unsigned int i = 0; i < ANIMATIONS_DEATHTYPES && i < args; ++i) {
		ExtraDeathTypes[i] = LuaToString(l, i + 1);
	}
	return 0;
}

UnitType


Get unit-type structure.

@param l Lua state.

@return Unit-type structure.

/unit/script_unittype.cpp:1587 CclUnitType

static int CclUnitType(lua_State *l)
{
	LuaCheckArgs(l, 1);

	const char *str = LuaToString(l, 1);
	CUnitType *type = UnitTypeByIdent(str);
	LuaUserData *data = (LuaUserData *)lua_newuserdata(l, sizeof(LuaUserData));
	data->Type = LuaUnitType;
	data->Data = type;
	return 1;
}

UnitTypeArray


Get all unit-type structures.

@param l Lua state.

@return An array of all unit-type structures.

/unit/script_unittype.cpp:1609 CclUnitTypeArray

static int CclUnitTypeArray(lua_State *l)
{
	LuaCheckArgs(l, 0);

	lua_newtable(l);

	for (std::vector<CUnitType *>::size_type i = 0; i < UnitTypes.size(); ++i) {
		LuaUserData *data = (LuaUserData *)lua_newuserdata(l, sizeof(LuaUserData));
		data->Type = LuaUnitType;
		data->Data = UnitTypes[i];
		lua_rawseti(l, 1, i + 1);
	}
	return 1;
}

GetUnitTypeIdent


Get the ident of the unit-type structure.

@param l Lua state.

@return The identifier of the unit-type.

/unit/script_unittype.cpp:1629 CclGetUnitTypeIdent

static int CclGetUnitTypeIdent(lua_State *l)
{
	LuaCheckArgs(l, 1);

	const CUnitType *type = CclGetUnitType(l);
	if (type) {
		lua_pushstring(l, type->Ident.c_str());
	} else {
		LuaError(l, "unit '%s' not defined" _C_ LuaToString(l, -1));
	}
	return 1;
}

GetUnitTypeName


Description

Get the name of the unit-type structure.

@param l Lua state.

@return The name of the unit-type.

Example:

name = GetUnitTypeName("unit-knight")
print(name)

/unit/script_unittype.cpp:1652 CclGetUnitTypeName

static int CclGetUnitTypeName(lua_State *l)
{
	LuaCheckArgs(l, 1);

	const CUnitType *type = CclGetUnitType(l);
	lua_pushstring(l, type->Name.c_str());
	return 1;
}

SetUnitTypeName


Description

Set the name of the unit-type structure.

@param l Lua state.

@return The name of the unit-type.

Example:

SetUnitTypeName("unit-beast-cry","Doomhammer")

/unit/script_unittype.cpp:1678 CclSetUnitTypeName

static int CclSetUnitTypeName(lua_State *l)
{
	LuaCheckArgs(l, 2);

	lua_pushvalue(l, 1);
	CUnitType *type = CclGetUnitType(l);
	lua_pop(l, 1);
	type->Name = LuaToString(l, 2);

	lua_pushvalue(l, 2);
	return 1;
}

GetUnitTypeData


Description

Get unit type data.

@param l Lua state.

Example:

-- Get the amount of supply from Human Farms
supply = GetUnitTypeData("unit-farm","Supply")
print(supply)

/unit/script_unittype.cpp:1902 CclGetUnitTypeData

static int CclGetUnitTypeData(lua_State *l)
{
	if (lua_gettop(l) < 2) {
		LuaError(l, "incorrect argument");
	}
	lua_pushvalue(l, 1);
	const CUnitType *type = CclGetUnitType(l);
	lua_pop(l, 1);
	const char *data = LuaToString(l, 2);

	if (!strcmp(data, "Name")) {
		lua_pushstring(l, type->Name.c_str());
		return 1;
	} else if (!strcmp(data, "Icon")) {
		lua_pushstring(l, type->Icon.Name.c_str());
		return 1;
	} else if (!strcmp(data, "Costs")) {
		LuaCheckArgs(l, 3);
		const std::string res = LuaToString(l, 3);
		const int resId = GetResourceIdByName(l, res.c_str());
		if (!GameRunning && Editor.Running != EditorEditing) {
			lua_pushnumber(l, type->DefaultStat.Costs[resId]);
		} else {
			lua_pushnumber(l, type->MapDefaultStat.Costs[resId]);
		}
		return 1;
	} else if (!strcmp(data, "ImproveProduction")) {
		LuaCheckArgs(l, 3);
		const std::string res = LuaToString(l, 3);
		const int resId = GetResourceIdByName(l, res.c_str());
		if (!GameRunning && Editor.Running != EditorEditing) {
			lua_pushnumber(l, type->DefaultStat.ImproveIncomes[resId]);
		} else {
			lua_pushnumber(l, type->MapDefaultStat.ImproveIncomes[resId]);
		}
		return 1;
	} else if (!strcmp(data, "DrawLevel")) {
		lua_pushnumber(l, type->DrawLevel);
		return 1;
	} else if (!strcmp(data, "TileWidth")) {
		lua_pushnumber(l, type->TileWidth);
		return 1;
	} else if (!strcmp(data, "TileHeight")) {
		lua_pushnumber(l, type->TileHeight);
		return 1;
	} else if (!strcmp(data, "ComputerReactionRange")) {
		lua_pushnumber(l, type->ReactRangeComputer);
		return 1;
	} else if (!strcmp(data, "PersonReactionRange")) {
		lua_pushnumber(l, type->ReactRangePerson);
		return 1;
	} else if (!strcmp(data, "Missile")) {
		lua_pushstring(l, type->Missile.Name.c_str());
		return 1;
	} else if (!strcmp(data, "MinAttackRange")) {
		lua_pushnumber(l, type->MinAttackRange);
		return 1;
	} else if (!strcmp(data, "MaxAttackRange")) {
		if (!GameRunning && Editor.Running != EditorEditing) {
			lua_pushnumber(l, type->DefaultStat.Variables[ATTACKRANGE_INDEX].Value);
		} else {
			lua_pushnumber(l, type->MapDefaultStat.Variables[ATTACKRANGE_INDEX].Value);
		}
		return 1;
	} else if (!strcmp(data, "Priority")) {
		if (!GameRunning && Editor.Running != EditorEditing) {
			lua_pushnumber(l, type->DefaultStat.Variables[PRIORITY_INDEX].Value);
		} else {
			lua_pushnumber(l, type->MapDefaultStat.Variables[PRIORITY_INDEX].Value);
		}
		return 1;
	} else if (!strcmp(data, "Type")) {
		if (type->UnitType == UnitTypeLand) {
			lua_pushstring(l, "land");
			return 1;
		} else if (type->UnitType == UnitTypeFly) {
			lua_pushstring(l, "fly");
			return 1;
		} else if (type->UnitType == UnitTypeNaval) {
			lua_pushstring(l, "naval");
			return 1;
		}
	} else if (!strcmp(data, "Corpse")) {
		lua_pushstring(l, type->CorpseName.c_str());
		return 1;
	} else if (!strcmp(data, "CanAttack")) {
		lua_pushboolean(l, type->CanAttack);
		return 1;
	} else if (!strcmp(data, "Building")) {
		lua_pushboolean(l, type->Building);
		return 1;
	} else if (!strcmp(data, "LandUnit")) {
		lua_pushboolean(l, type->LandUnit);
		return 1;
	} else if (!strcmp(data, "GivesResource")) {
		if (type->GivesResource > 0) {
			lua_pushstring(l, DefaultResourceNames[type->GivesResource].c_str());
			return 1;
		} else {
			lua_pushstring(l, "");
			return 1;
		}
	} else if (!strcmp(data, "Sounds")) {
		LuaCheckArgs(l, 3);
		const std::string sound_type = LuaToString(l, 3);
		if (sound_type == "selected") {
			if (!GameRunning && Editor.Running != EditorEditing) {
				lua_pushstring(l, type->Sound.Selected.Name.c_str());
			} else {
				lua_pushstring(l, type->MapSound.Selected.Name.c_str());
			}
		} else if (sound_type == "acknowledge") {
			if (!GameRunning && Editor.Running != EditorEditing) {
				lua_pushstring(l, type->Sound.Acknowledgement.Name.c_str());
			} else {
				lua_pushstring(l, type->MapSound.Acknowledgement.Name.c_str());
			}
		} else if (sound_type == "attack") {
			if (!GameRunning && Editor.Running != EditorEditing) {
				lua_pushstring(l, type->Sound.Attack.Name.c_str());
			} else {
				lua_pushstring(l, type->MapSound.Attack.Name.c_str());
			}
		} else if (sound_type == "build") {
			if (!GameRunning && Editor.Running != EditorEditing) {
				lua_pushstring(l, type->Sound.Build.Name.c_str());
			} else {
				lua_pushstring(l, type->MapSound.Build.Name.c_str());
			}
		} else if (sound_type == "ready") {
			if (!GameRunning && Editor.Running != EditorEditing) {
				lua_pushstring(l, type->Sound.Ready.Name.c_str());
			} else {
				lua_pushstring(l, type->MapSound.Ready.Name.c_str());
			}
		} else if (sound_type == "repair") {
			if (!GameRunning && Editor.Running != EditorEditing) {
				lua_pushstring(l, type->Sound.Repair.Name.c_str());
			} else {
				lua_pushstring(l, type->MapSound.Repair.Name.c_str());
			}
		} else if (sound_type == "harvest") {
			LuaCheckArgs(l, 4);
			const std::string sound_subtype = LuaToString(l, 4);
			const int resId = GetResourceIdByName(sound_subtype.c_str());
			if (!GameRunning && Editor.Running != EditorEditing) {
				lua_pushstring(l, type->Sound.Harvest[resId].Name.c_str());
			} else {
				lua_pushstring(l, type->MapSound.Harvest[resId].Name.c_str());
			}
		} else if (sound_type == "help") {
			if (!GameRunning && Editor.Running != EditorEditing) {
				lua_pushstring(l, type->Sound.Help.Name.c_str());
			} else {
				lua_pushstring(l, type->MapSound.Help.Name.c_str());
			}
		} else if (sound_type == "dead") {
			if (lua_gettop(l) < 4) {
				if (!GameRunning && Editor.Running != EditorEditing) {
					lua_pushstring(l, type->Sound.Dead[ANIMATIONS_DEATHTYPES].Name.c_str());
				} else {
					lua_pushstring(l, type->MapSound.Dead[ANIMATIONS_DEATHTYPES].Name.c_str());
				}
			} else {
				int death;
				const std::string sound_subtype = LuaToString(l, 4);

				for (death = 0; death < ANIMATIONS_DEATHTYPES; ++death) {
					if (sound_subtype == ExtraDeathTypes[death]) {
						break;
					}
				}
				if (death == ANIMATIONS_DEATHTYPES) {
					if (!GameRunning && Editor.Running != EditorEditing) {
						lua_pushstring(l, type->Sound.Dead[ANIMATIONS_DEATHTYPES].Name.c_str());
					} else {
						lua_pushstring(l, type->MapSound.Dead[ANIMATIONS_DEATHTYPES].Name.c_str());
					}
				} else {
					if (!GameRunning && Editor.Running != EditorEditing) {
						lua_pushstring(l, type->Sound.Dead[death].Name.c_str());
					} else {
						lua_pushstring(l, type->MapSound.Dead[death].Name.c_str());
					}
				}
			}
		}
		return 1;
	} else {
		int index = UnitTypeVar.VariableNameLookup[data];
		if (index != -1) { // valid index
			if (!GameRunning && Editor.Running != EditorEditing) {
				lua_pushnumber(l, type->DefaultStat.Variables[index].Value);
			} else {
				lua_pushnumber(l, type->MapDefaultStat.Variables[index].Value);
			}
			return 1;
		}

		index = UnitTypeVar.BoolFlagNameLookup[data];
		if (index != -1) {
			lua_pushboolean(l, type->BoolFlag[index].value);
			return 1;
		} else {
			LuaError(l, "Invalid field: %s" _C_ data);
		}
	}

	return 0;
}


/missile/script_missile.cpp
DefineMissileType


Parse missile-type.

@param l Lua state.

/missile/script_missile.cpp:239 CclDefineMissileType

static int CclDefineMissileType(lua_State *l)
{
	LuaCheckArgs(l, 2);
	if (!lua_istable(l, 2)) {
		LuaError(l, "incorrect argument");
	}

	// Slot identifier
	const char *str = LuaToString(l, 1);
	MissileType *mtype = MissileTypeByIdent(str);

	if (mtype) {
		DebugPrint("Redefining missile-type '%s'\n" _C_ str);
	} else {
		mtype = NewMissileTypeSlot(str);
	}
	mtype->Load(l);
	return 0;
}

Missile


Create a missile.

@param l Lua state.

/missile/script_missile.cpp:337 CclMissile

static int CclMissile(lua_State *l)
{
	MissileType *type = NULL;
	PixelPos position(-1, -1);
	PixelPos destination(-1, -1);
	PixelPos source(-1, -1);
	Missile *missile = NULL;

	DebugPrint("FIXME: not finished\n");

	const int args = lua_gettop(l);
	for (int j = 0; j < args; ++j) {
		const char *value = LuaToString(l, j + 1);
		++j;

		if (!strcmp(value, "type")) {
			type = MissileTypeByIdent(LuaToString(l, j + 1));
		} else if (!strcmp(value, "pos")) {
			CclGetPos(l, &position.x, &position.y, j + 1);
		} else if (!strcmp(value, "origin-pos")) {
			CclGetPos(l, &source.x, &source.y, j + 1);
		} else if (!strcmp(value, "goal")) {
			CclGetPos(l, &destination.x, &destination.y, j + 1);
		} else if (!strcmp(value, "local")) {
			Assert(type);
			missile = MakeLocalMissile(*type, position, destination);
			missile->Local = 1;
			--j;
		} else if (!strcmp(value, "global")) {
			Assert(type);
			missile = MakeMissile(*type, position, destination);
			missile->position = position;
			missile->source = source;
			missile->destination = destination;
			missile->Local = 0;
			--j;
		} else if (!strcmp(value, "frame")) {
			Assert(missile);
			missile->SpriteFrame = LuaToNumber(l, j + 1);
		} else if (!strcmp(value, "state")) {
			Assert(missile);
			missile->State = LuaToNumber(l, j + 1);
		} else if (!strcmp(value, "anim-wait")) {
			Assert(missile);
			missile->AnimWait = LuaToNumber(l, j + 1);
		} else if (!strcmp(value, "wait")) {
			Assert(missile);
			missile->Wait = LuaToNumber(l, j + 1);
		} else if (!strcmp(value, "delay")) {
			Assert(missile);
			missile->Delay = LuaToNumber(l, j + 1);
		} else if (!strcmp(value, "source")) {
			Assert(missile);
			lua_pushvalue(l, j + 1);
			missile->SourceUnit = CclGetUnitFromRef(l);
			lua_pop(l, 1);
		} else if (!strcmp(value, "target")) {
			Assert(missile);
			lua_pushvalue(l, j + 1);
			missile->TargetUnit = CclGetUnitFromRef(l);
			lua_pop(l, 1);
		} else if (!strcmp(value, "damage")) {
			Assert(missile);
			missile->Damage = LuaToNumber(l, j + 1);
		} else if (!strcmp(value, "ttl")) {
			Assert(missile);
			missile->TTL = LuaToNumber(l, j + 1);
		} else if (!strcmp(value, "hidden")) {
			Assert(missile);
			missile->Hidden = 1;
			--j;
		} else if (!strcmp(value, "step")) {
			Assert(missile);
			if (!lua_istable(l, j + 1) || lua_rawlen(l, j + 1) != 2) {
				LuaError(l, "incorrect argument");
			}
			missile->CurrentStep = LuaToNumber(l, j + 1, 1);
			missile->TotalStep = LuaToNumber(l, j + 1, 2);
		} else {
			LuaError(l, "Unsupported tag: %s" _C_ value);
		}
	}

	// we need to reinitialize position parameters - that's because of
	// the way InitMissile() (called from MakeLocalMissile()) computes
	// them - it works for creating a missile during a game but breaks
	// loading the missile from a file.
	missile->position = position;
	missile->source = source;
	missile->destination = destination;
	return 0;
}

DefineBurningBuilding


Define burning building missiles.

@param l Lua state.

/missile/script_missile.cpp:373 CclDefineBurningBuilding

static int CclDefineBurningBuilding(lua_State *l)
{
	for (std::vector<BurningBuildingFrame *>::iterator i = BurningBuildingFrames.begin();
		 i != BurningBuildingFrames.end(); ++i) {
		delete *i;
	}
	BurningBuildingFrames.clear();

	const int args = lua_gettop(l);
	for (int j = 0; j < args; ++j) {
		if (!lua_istable(l, j + 1)) {
			LuaError(l, "incorrect argument");
		}
		BurningBuildingFrame *ptr = new BurningBuildingFrame;
		const int subargs = lua_rawlen(l, j + 1);

		for (int k = 0; k < subargs; ++k) {
			const char *value = LuaToString(l, j + 1, k + 1);
			++k;

			if (!strcmp(value, "percent")) {
				ptr->Percent = LuaToNumber(l, j + 1, k + 1);
			} else if (!strcmp(value, "missile")) {
				ptr->Missile = MissileTypeByIdent(LuaToString(l, j + 1, k + 1));
			}
		}
		BurningBuildingFrames.insert(BurningBuildingFrames.begin(), ptr);
	}
	return 0;
}

CreateMissile


Create a missile on the map

@param l Lua state.

/missile/script_missile.cpp:422 CclCreateMissile

static int CclCreateMissile(lua_State *l)
{
	const int arg = lua_gettop(l);
	if (arg < 6 || arg > 7) {
		LuaError(l, "incorrect argument");
	}

	const std::string name = LuaToString(l, 1);
	const MissileType *mtype = MissileTypeByIdent(name);
	if (!mtype) {
		LuaError(l, "Bad missile");
	}
	PixelPos startpos, endpos;
	CclGetPos(l, &startpos.x, &startpos.y, 2);
	CclGetPos(l, &endpos.x, &endpos.y, 3);

	const int sourceUnitId = LuaToNumber(l, 4);
	const int destUnitId = LuaToNumber(l, 5);
	const bool dealDamage = LuaToBoolean(l, 6);
	const bool mapRelative = arg == 7 ? LuaToBoolean(l, 7) : false;
	CUnit *sourceUnit = sourceUnitId != -1 ? &UnitManager->GetSlotUnit(sourceUnitId) : NULL;
	CUnit *destUnit = destUnitId != -1 ? &UnitManager->GetSlotUnit(destUnitId) : NULL;

	if (mapRelative == false) {
		if (sourceUnit != NULL) {
			startpos += sourceUnit->GetMapPixelPosTopLeft();
		}
		if (destUnit != NULL) {
			endpos += destUnit->GetMapPixelPosTopLeft();
		}
	}

	Missile *missile = MakeMissile(*mtype, startpos, endpos);
	if (!missile) {
		return 0;
	}
	if (dealDamage) {
		missile->SourceUnit = sourceUnit;
	}
	missile->TargetUnit = destUnit;
	return 0;
}


/video/shaders.cpp
GetShaderNames


Description

Get the list of shaders.

Example:

shaders = GetShaderNames()
for i,name in ipairs(shaders) do
print(name)
end

/video/shaders.cpp:482 CclGetShaderNames

static int CclGetShaderNames(lua_State *l) {
	LuaCheckArgs(l, 0);
	lua_newtable(l);
	for (int i = 0; shaderNames[i] != NULL; i++) {
		lua_pushstring(l, shaderNames[i]);
		lua_rawseti(l, -2, i + 1);
	}
	return 1;
}

GetShader


Description

Get the active shader.

Example:

shader_name = GetShader()
print(shader_name)

/video/shaders.cpp:429 CclGetShader

static int CclGetShader(lua_State *l) {
	LuaCheckArgs(l, 0);
	const char* shaderName = shaderNames[currentShaderIdx];
	if (shaderName) {
		lua_pushstring(l, shaderName);
	} else {
		lua_pushnil(l);
	}
	return 1;
}

SetShader


Description

Apply a shader.

Example:

-- Apply a VHS shader
SetShader("VHS")

/video/shaders.cpp:460 CclSetShader

static int CclSetShader(lua_State *l) {
	LuaCheckArgs(l, 1);
	const char* shaderName = LuaToString(l, 1);
	for (int i = 0; i < MAX_SHADERS; i++) {
		const char* n = shaderNames[i];
		if (n) {
			if (!strcmp(n, shaderName)) {
				currentShaderIdx = i;
				std::cout << "SetShader: " << shaderNames[currentShaderIdx] << std::endl;
				lua_pushboolean(l, 1);
				return 1;
			}
		} else {
			break;
		}
	}
	currentShaderIdx = 0;
	lua_pushboolean(l, 0);
	return 1;
}


/video/video.cpp
SetVideoSyncSpeed


Set the video sync speed

@param l Lua state.

/video/video.cpp:353 CclSetVideoSyncSpeed

static int CclSetVideoSyncSpeed(lua_State *l)
{
	LuaCheckArgs(l, 1);
	VideoSyncSpeed = LuaToNumber(l, 1);
	return 0;
}


/video/cursor.cpp
DefineCursor


Define a cursor.

@param l Lua state.

/video/cursor.cpp:524 CclDefineCursor

static int CclDefineCursor(lua_State *l)
{
	std::string name;
	std::string race;
	std::string file;
	PixelPos hotpos(0, 0);
	int w = 0;
	int h = 0;
	int rate = 0;

	LuaCheckArgs(l, 1);
	if (!lua_istable(l, 1)) {
		LuaError(l, "incorrect argument");
	}
	lua_pushnil(l);
	while (lua_next(l, 1)) {
		const char *value = LuaToString(l, -2);
		if (!strcmp(value, "Name")) {
			name = LuaToString(l, -1);
		} else if (!strcmp(value, "Race")) {
			race = LuaToString(l, -1);
		} else if (!strcmp(value, "File")) {
			file = LuaToString(l, -1);
		} else if (!strcmp(value, "HotSpot")) {
			CclGetPos(l, &hotpos.x, &hotpos.y);
		} else if (!strcmp(value, "Size")) {
			CclGetPos(l, &w, &h);
		} else if (!strcmp(value, "Rate")) {
			rate = LuaToNumber(l, -1);
		} else {
			LuaError(l, "Unsupported tag: %s" _C_ value);
		}
		lua_pop(l, 1);
	}

	Assert(!name.empty() && !file.empty() && w && h);

	if (race == "any") {
		race.clear();
	}

	//
	//  Look if this kind of cursor already exists.
	//
	CCursor *ct = NULL;
	for (size_t i = 0; i < AllCursors.size(); ++i) {
		//  Race not same, not found.
		if (AllCursors[i]->Race != race) {
			continue;
		}
		if (AllCursors[i]->Ident == name) {
			ct = AllCursors[i];
			break;
		}
	}

	//
	//  Not found, make a new slot.
	//
	if (!ct) {
		ct = new CCursor();
		AllCursors.push_back(ct);
		ct->Ident = name;
		ct->Race = race;
	}
	ct->G = CGraphic::New(file, w, h);
	ct->HotPos = hotpos;
	ct->FrameRate = rate;

	return 0;
}

SetGameCursor


Set the current game cursor.

@param l Lua state.

/video/cursor.cpp:536 CclSetGameCursor

static int CclSetGameCursor(lua_State *l)
{
	LuaCheckArgs(l, 1);
	GameCursor = CursorByIdent(LuaToString(l, 1));
	return 0;
}


/animation/animation.cpp
DefineAnimations


Define a unit-type animation set.

@param l Lua state.

/animation/animation.cpp:761 CclDefineAnimations

static int CclDefineAnimations(lua_State *l)
{
	LuaCheckArgs(l, 2);
	if (!lua_istable(l, 2)) {
		LuaError(l, "incorrect argument");
	}

	const char *name = LuaToString(l, 1);
	CAnimations *anims = AnimationsByIdent(name);
	if (!anims) {
		anims = new CAnimations;
		AnimationMap[name] = anims;
	}

	lua_pushnil(l);
	while (lua_next(l, 2)) {
		const char *value = LuaToString(l, -2);

		if (!strcmp(value, "Start")) {
			anims->Start = ParseAnimation(l, -1);
		} else if (!strncmp(value, "Still", 5)) {
			anims->Still = ParseAnimation(l, -1);
		} else if (!strncmp(value, "Death", 5)) {
			anims->hasDeathAnimation = true;
			if (strlen(value) > 5) {
				const int death = ExtraDeathIndex(value + 6);
				if (death == ANIMATIONS_DEATHTYPES) {
					anims->Death[ANIMATIONS_DEATHTYPES] = ParseAnimation(l, -1);
				} else {
					anims->Death[death] = ParseAnimation(l, -1);
				}
			} else {
				anims->Death[ANIMATIONS_DEATHTYPES] = ParseAnimation(l, -1);
			}
		} else if (!strcmp(value, "Attack")) {
			anims->Attack = ParseAnimation(l, -1);
		} else if (!strcmp(value, "RangedAttack")) {
			anims->RangedAttack = ParseAnimation(l, -1);
		} else if (!strcmp(value, "SpellCast")) {
			anims->SpellCast = ParseAnimation(l, -1);
		} else if (!strcmp(value, "Move")) {
			anims->Move = ParseAnimation(l, -1);
		} else if (!strcmp(value, "Repair")) {
			anims->Repair = ParseAnimation(l, -1);
		} else if (!strcmp(value, "Train")) {
			anims->Train = ParseAnimation(l, -1);
		} else if (!strcmp(value, "Research")) {
			anims->Research = ParseAnimation(l, -1);
		} else if (!strcmp(value, "Upgrade")) {
			anims->Upgrade = ParseAnimation(l, -1);
		} else if (!strcmp(value, "Build")) {
			anims->Build = ParseAnimation(l, -1);
		} else if (!strncmp(value, "Harvest_", 8)) {
			const int res = GetResourceIdByName(l, value + 8);
			anims->Harvest[res] = ParseAnimation(l, -1);
		} else {
			LuaError(l, "Unsupported animation: %s" _C_ value);
		}
		lua_pop(l, 1);
	}
	// Must add to array in a fixed order for save games
	AddAnimationToArray(anims->Start);
	AddAnimationToArray(anims->Still);
	for (int i = 0; i != ANIMATIONS_DEATHTYPES + 1; ++i) {
		AddAnimationToArray(anims->Death[i]);
	}
	AddAnimationToArray(anims->Attack);
	AddAnimationToArray(anims->RangedAttack);
	AddAnimationToArray(anims->SpellCast);
	AddAnimationToArray(anims->Move);
	AddAnimationToArray(anims->Repair);
	AddAnimationToArray(anims->Train);
	for (int i = 0; i != MaxCosts; ++i) {
		AddAnimationToArray(anims->Harvest[i]);
	}
	return 0;
}


/sound/script_sound.cpp
SetGlobalSoundRange


Description

Set the cut off distance.

@param l Lua state.

Example:

SetGlobalSoundRange(200)

/sound/script_sound.cpp:338 CclSetGlobalSoundRange

static int CclSetGlobalSoundRange(lua_State *l)
{
	LuaCheckArgs(l, 1);

	// FIXME: check for errors
	int d = LuaToNumber(l, 1);
	if (d > 0) {
		DistanceSilent = d;
	}
	return 0;
}

DefineGameSounds


Glue between c and scheme. Allows to specify some global game sounds
in a ccl file.

@param l Lua state.

/sound/script_sound.cpp:315 CclDefineGameSounds

static int CclDefineGameSounds(lua_State *l)
{
	//FIXME: should allow to define ALL the game sounds

	const int args = lua_gettop(l);
	for (int j = 0; j < args; ++j) {
		const char *value = LuaToString(l, j + 1);
		++j;

		LuaUserData *data = NULL;

		// let's handle now the different cases
		if (!strcmp(value, "click")) {
			if (!lua_isuserdata(l, j + 1)
				|| (data = (LuaUserData *)lua_touserdata(l, j + 1))->Type != LuaSoundType) {
				LuaError(l, "Sound id expected");
			}
			GameSounds.Click.Sound = (CSound *)data->Data;
		} else if (!strcmp(value, "transport-docking")) {
			if (!lua_isuserdata(l, j + 1)
				|| (data = (LuaUserData *)lua_touserdata(l, j + 1))->Type != LuaSoundType) {
				LuaError(l, "Sound id expected");
			}
			GameSounds.Docking.Sound = (CSound *)data->Data;
		} else if (!strcmp(value, "placement-error")) {
			SetSoundConfigRace(l, j, GameSounds.PlacementError);
		} else if (!strcmp(value, "placement-success")) {
			SetSoundConfigRace(l, j, GameSounds.PlacementSuccess);
		} else if (!strcmp(value, "work-complete")) {
			SetSoundConfigRace(l, j, GameSounds.WorkComplete);
		} else if (!strcmp(value, "research-complete")) {
			SetSoundConfigRace(l, j, GameSounds.ResearchComplete);
		} else if (!strcmp(value, "not-enough-res")) {
			if (!lua_istable(l, j + 1) || lua_rawlen(l, j + 1) != 3) {
				LuaError(l, "incorrect argument");
			}
			const char *resName = LuaToString(l, j + 1, 1);
			const int resId = GetResourceIdByName(l, resName);
			const char *raceName = LuaToString(l, j + 1, 2);
			const int raceIndex = PlayerRaces.GetRaceIndexByName(raceName);
			if (raceIndex == -1) {
				LuaError(l, "Unknown race: %s" _C_ raceName);
			}
			lua_rawgeti(l, j + 1, 3);
			if (!lua_isuserdata(l, -1)
				|| (data = (LuaUserData *)lua_touserdata(l, -1))->Type != LuaSoundType) {
				LuaError(l, "Sound id expected");
			}
			lua_pop(l, 1);
			GameSounds.NotEnoughRes[raceIndex][resId].Sound = (CSound *)data->Data;
		} else if (!strcmp(value, "not-enough-food")) {
			SetSoundConfigRace(l, j, GameSounds.NotEnoughFood);
		} else if (!strcmp(value, "rescue")) {
			SetSoundConfigRace(l, j, GameSounds.Rescue);
		} else if (!strcmp(value, "building-construction")) {
			SetSoundConfigRace(l, j, GameSounds.BuildingConstruction);
		} else if (!strcmp(value, "chat-message")) {
			if (!lua_isuserdata(l, j + 1)
				|| (data = (LuaUserData *)lua_touserdata(l, j + 1))->Type != LuaSoundType) {
				LuaError(l, "Sound id expected");
			}
			GameSounds.ChatMessage.Sound = (CSound *)data->Data;
		} else {
			LuaError(l, "Unsupported tag: %s" _C_ value);
		}
	}
	return 0;
}

MapSound


Glue between c and scheme. Ask to the sound system to remap a sound id
to a given name.

@param l Lua state.

@return the sound object

/sound/script_sound.cpp:191 CclMapSound

static int CclMapSound(lua_State *l)
{
	const char *sound_name;

	LuaCheckArgs(l, 2);
	sound_name = LuaToString(l, 1);
	MapSound(sound_name, CclGetSound(l));
	lua_pushvalue(l, 2);
	return 1;
}

SoundForName


Glue between c and scheme. Ask the sound system to associate a
sound id to a sound name.

@param l Lua state.

/sound/script_sound.cpp:71 CclSoundForName

static int CclSoundForName(lua_State *l)
{
	CSound *id;
	const char *sound_name;
	LuaUserData *data;

	sound_name = LuaToString(l, -1);
	id = SoundForName(sound_name);

	data = (LuaUserData *)lua_newuserdata(l, sizeof(LuaUserData));
	data->Type = LuaSoundType;
	data->Data = id;
	return 1;
}

SetSoundRange


Set the range of a given sound.

@param l Lua state.

/sound/script_sound.cpp:358 CclSetSoundRange

static int CclSetSoundRange(lua_State *l)
{

	LuaCheckArgs(l, 2);

	int tmp = LuaToNumber(l, 2);
	clamp(&tmp, 0, 255);
	const unsigned char theRange = static_cast<unsigned char>(tmp);

	lua_pushvalue(l, 1);
	CSound *id = CclGetSound(l);
	SetSoundRange(id, theRange);
	return 1;
}

MakeSound


Create a sound.

Glue between c and scheme. This function asks the sound system to
register a sound under a given name, with an associated list of files
(the list can be replaced by only one file).

@param l Lua state.

@return the sound id of the created sound

/sound/script_sound.cpp:141 CclMakeSound

static int CclMakeSound(lua_State *l)
{
	LuaCheckArgs(l, 2);

	std::string c_name = LuaToString(l, 1);
	std::vector<std::string> files;
	CSound *id;
	if (lua_isstring(l, 2)) {
		// only one file
		files.push_back(LuaToString(l, 2));
		id = MakeSound(c_name, files);
	} else if (lua_istable(l, 2)) {
		// several files
		const int args = lua_rawlen(l, 2);
		files.reserve(args);
		for (int j = 0; j < args; ++j) {
			files.push_back(LuaToString(l, 2, j + 1));
		}
		id = MakeSound(c_name, files);
	} else {
		LuaError(l, "string or table expected");
		return 0;
	}
	LuaUserData *data = (LuaUserData *)lua_newuserdata(l, sizeof(LuaUserData));
	data->Type = LuaSoundType;
	data->Data = id;
	return 1;
}

MakeSoundGroup


Glue between c and scheme. This function asks the sound system to
build a special sound group.

@param l Lua state.

@return The sound id of the created sound

/sound/script_sound.cpp:172 CclMakeSoundGroup

static int CclMakeSoundGroup(lua_State *l)
{
	CSound *id;
	std::string c_name;
	CSound *first;
	CSound *second;
	LuaUserData *data;

	LuaCheckArgs(l, 3);

	c_name = LuaToString(l, 1);

	lua_pushvalue(l, 2);
	first = CclGetSound(l);
	lua_pop(l, 1);
	second = CclGetSound(l);
	id = MakeSoundGroup(c_name, first, second);
	data = (LuaUserData *)lua_newuserdata(l, sizeof(LuaUserData));
	data->Type = LuaSoundType;
	data->Data = id;
	return 1;
}

PlaySound


Description

Ask the sound system to play the specified sound.

@param l Lua state.

Example:

PlaySound("rescue (orc)")

/sound/script_sound.cpp:220 CclPlaySound

static int CclPlaySound(lua_State *l)
{
	const int args = lua_gettop(l);
	if (args < 1 || args > 2) {
		LuaError(l, "incorrect argument");
	}

	lua_pushvalue(l, 1);
	CSound *id = CclGetSound(l);
	lua_pop(l, 1);
	bool always = false;
	if (args == 2) {
		always = LuaToBoolean(l, 2);
	}
	PlayGameSound(id, MaxSampleVolume, always);
	return 0;
}


/map/script_map.cpp
StratagusMap


Parse a map.

@param l Lua state.

/map/script_map.cpp:135 CclStratagusMap

static int CclStratagusMap(lua_State *l)
{
	int args = lua_gettop(l);
	for (int j = 0; j < args; ++j) {
		const char *value = LuaToString(l, j + 1);
		++j;

		if (!strcmp(value, "version")) {
			char buf[32];

			const char *version = LuaToString(l, j + 1);
			strncpy(buf, VERSION, sizeof(buf));
			if (strcmp(buf, version)) {
				fprintf(stderr, "Warning not saved with this version.\n");
			}
		} else if (!strcmp(value, "uid")) {
			Map.Info.MapUID = LuaToNumber(l, j + 1);
		} else if (!strcmp(value, "description")) {
			Map.Info.Description = LuaToString(l, j + 1);
		} else if (!strcmp(value, "the-map")) {
			if (!lua_istable(l, j + 1)) {
				LuaError(l, "incorrect argument");
			}
			int subargs = lua_rawlen(l, j + 1);
			for (int k = 0; k < subargs; ++k) {
				const char *value = LuaToString(l, j + 1, k + 1);
				++k;

				if (!strcmp(value, "size")) {
					lua_rawgeti(l, j + 1, k + 1);
					CclGetPos(l, &Map.Info.MapWidth, &Map.Info.MapHeight);
					lua_pop(l, 1);

					delete[] Map.Fields;
					Map.Fields = new CMapField[Map.Info.MapWidth * Map.Info.MapHeight];
					// FIXME: this should be CreateMap or InitMap?
				} else if (!strcmp(value, "fog-of-war")) {
					Map.NoFogOfWar = false;
					--k;
				} else if (!strcmp(value, "no-fog-of-war")) {
					Map.NoFogOfWar = true;
					--k;
				} else if (!strcmp(value, "filename")) {
					Map.Info.Filename = LuaToString(l, j + 1, k + 1);
				} else if (!strcmp(value, "map-fields")) {
					lua_rawgeti(l, j + 1, k + 1);
					if (!lua_istable(l, -1)) {
						LuaError(l, "incorrect argument");
					}
					const int subsubargs = lua_rawlen(l, -1);
					if (subsubargs != Map.Info.MapWidth * Map.Info.MapHeight) {
						fprintf(stderr, "Wrong tile table length: %d\n", subsubargs);
					}
					for (int i = 0; i < subsubargs; ++i) {
						lua_rawgeti(l, -1, i + 1);
						if (!lua_istable(l, -1)) {
							LuaError(l, "incorrect argument");
						}
						Map.Fields[i].parse(l);
						lua_pop(l, 1);
					}
					lua_pop(l, 1);
				} else {
					LuaError(l, "Unsupported tag: %s" _C_ value);
				}
			}
		} else {
			LuaError(l, "Unsupported tag: %s" _C_ value);
		}
	}
	return 0;
}

RevealMap


Reveal the complete map.

@param l Lua state.

/map/script_map.cpp:168 CclRevealMap

static int CclRevealMap(lua_State *l)
{
	LuaCheckArgs(l, 1);

	MapRevealModes newMode;
	const char *revealMode = LuaToString(l, 1);
	if (!strcmp(revealMode, "hidden")) {
		newMode = MapRevealModes::cHidden;
	} else 	if (!strcmp(revealMode, "known")) {
		newMode = MapRevealModes::cKnown;
	} else if (!strcmp(revealMode, "explored")) {
		newMode = MapRevealModes::cExplored;
	} else {
		PrintFunction();
		fprintf(stdout, "Accessible reveal modes: \"hidden\", \"known\", \"explored\".\n");
		return 1;
	}

	if (CclInConfigFile || !Map.Fields) {
		FlagRevealMap = newMode;
	} else if (!IsNetworkGame()) {
		Map.Reveal(newMode);
	} else {
		NetworkSendExtendedCommand(ExtendedMessageRevealMapDB, int(newMode), 0, 0, 0, 0);
	}
	return 0;
}

CenterMap


Description

Center the map.

@param l Lua state.

Example:

-- Center the view at position x=11 and y=1.
CenterMap(11, 1)

/map/script_map.cpp:189 CclCenterMap

static int CclCenterMap(lua_State *l)
{
	LuaCheckArgs(l, 2);
	const Vec2i pos(LuaToNumber(l, 1), LuaToNumber(l, 2));

	UI.SelectedViewport->Center(Map.TilePosToMapPixelPos_Center(pos));
	return 0;
}

SetStartView


Description

Define the starting viewpoint for a given player.

@param l Lua state.

Example:

-- Start view for player 0.
SetStartView(0, 25, 12)
-- Start view for player 1.
SetStartView(1, 71, 38)

/map/script_map.cpp:214 CclSetStartView

static int CclSetStartView(lua_State *l)
{
	LuaCheckArgs(l, 3);

	const int p = LuaToNumber(l, 1);
	Players[p].StartPos.x = LuaToNumber(l, 2);
	Players[p].StartPos.y = LuaToNumber(l, 3);

	return 0;
}

ShowMapLocation


Show Map Location

@param l Lua state.

/map/script_map.cpp:245 CclShowMapLocation

static int CclShowMapLocation(lua_State *l)
{
	// Put a unit on map, use its properties, except for
	// what is listed below

	LuaCheckArgs(l, 5);
	const char *unitname = LuaToString(l, 5);
	CUnitType *unitType = UnitTypeByIdent(unitname);
	if (!unitType) {
		DebugPrint("Unable to find UnitType '%s'" _C_ unitname);
		return 0;
	}
	CUnit *target = MakeUnit(*unitType, ThisPlayer);
	if (target != NULL) {
		target->Variable[HP_INDEX].Value = 0;
		target->tilePos.x = LuaToNumber(l, 1);
		target->tilePos.y = LuaToNumber(l, 2);
		target->TTL = GameCycle + LuaToNumber(l, 4);
		target->CurrentSightRange = LuaToNumber(l, 3);
		MapMarkUnitSight(*target);
	} else {
		DebugPrint("Unable to allocate Unit");
	}
	return 0;
}

SetTileSize


Description

Define size in pixels (x,y) of a tile in this game

@param l Lua state.

Example:

SetTileSize(32,32)

/map/script_map.cpp:743 CclSetTileSize

static int CclSetTileSize(lua_State *l)
{
	LuaCheckArgs(l, 2);
	PixelTileSize.x = LuaToNumber(l, 1);
	PixelTileSize.y = LuaToNumber(l, 2);
	return 0;
}

SetFogOfWar


Description

Set fog of war on/off.

Example:

SetFogOfWar(true)


@param l Lua state.

/map/script_map.cpp:269 CclSetFogOfWar

static int CclSetFogOfWar(lua_State *l)
{

	LuaCheckArgs(l, 1);
	Map.NoFogOfWar = !LuaToBoolean(l, 1);
	if (!CclInConfigFile && Map.Fields) {
		UpdateFogOfWarChange();
		// FIXME: save setting in replay log
		//CommandLog("input", NoUnitP, FlushCommands, -1, -1, NoUnitP, "fow off", -1);
	}
	return 0;
}

GetFogOfWar


Description

Get if the fog of war is enabled.

@param l Lua state.

Example:

GetFogOfWar()

/map/script_map.cpp:287 CclGetFogOfWar

static int CclGetFogOfWar(lua_State *l)
{
	LuaCheckArgs(l, 0);
	lua_pushboolean(l, !Map.NoFogOfWar);
	return 1;
}

SetMinimapTerrain


Description

Enable display of terrain in minimap.

@param l Lua state.

Example:

-- Show the minimap terrain
SetMinimapTerrain(true)

/map/script_map.cpp:306 CclSetMinimapTerrain

static int CclSetMinimapTerrain(lua_State *l)
{
	LuaCheckArgs(l, 1);
	UI.Minimap.WithTerrain = LuaToBoolean(l, 1);
	return 0;
}

SetEnableMapGrid


Activate map grid (true|false)

@param l Lua state.

@return 0 for success, 1 for wrong type;

/map/script_map.cpp:320 CclSetEnableMapGrid

static int CclSetEnableMapGrid(lua_State *l)
{
	LuaCheckArgs(l, 1);
	CViewport::EnableGrid(LuaToBoolean(l, 1));
	return 0;
}

GetIsMapGridEnabled


Check if map grid is enabled

/map/script_map.cpp:330 CclGetIsMapGridEnabled

static int CclGetIsMapGridEnabled(lua_State *l)
{
	LuaCheckArgs(l, 0);
	lua_pushboolean(l, CViewport::isGridEnabled());
	return 1;
}

SetFieldOfViewType


Select unit's field of view algorithm - ShadowCasting or SimpleRadial

@param l Lua state.

@return 0 for success, 1 for wrong type;

/map/script_map.cpp:364 CclSetFieldOfViewType

static int CclSetFieldOfViewType(lua_State *l)
{
	LuaCheckArgs(l, 1);

	FieldOfViewTypes new_type;
	const char *type_name = LuaToString(l, 1);
	if (!strcmp(type_name, "shadow-casting")) {
		new_type = FieldOfViewTypes::cShadowCasting;
		/// Tiled types of FOW don't work with shadow casting
		if (FogOfWar->GetType() != FogOfWarTypes::cEnhanced) {
			FogOfWar->SetType(FogOfWarTypes::cEnhanced);
		}
	} else if (!strcmp(type_name, "simple-radial")) {
		new_type = FieldOfViewTypes::cSimpleRadial;
	} else {
		PrintFunction();
		fprintf(stdout, "Accessible Field of View types: \"shadow-casting\", \"simple-radial\".\n");
		return 1;
	}
	if (!IsNetworkGame()) {
		FieldOfView.SetType(new_type);
	} else {
		NetworkSendExtendedCommand(ExtendedMessageFieldOfViewDB, int(new_type), 0, 0, 0, 0);
	}
	return 0;
}

GetFieldOfViewType


Get unit's field of view type - ShadowCasting or SimpleRadial

/map/script_map.cpp:374 CclGetFieldOfViewType

static int CclGetFieldOfViewType(lua_State *l)
{
	LuaCheckArgs(l, 0);
	lua_pushinteger(l, int(FieldOfView.GetType()));
	return 1;
}

SetOpaqueFor


Set opaque for the tile's terrain.

@param l Lua state.

@return 0 for success, 1 for wrong tile's terrain;

/map/script_map.cpp:412 CclSetOpaqueFor

static int CclSetOpaqueFor(lua_State *l)
{
	uint16_t new_flag = 0;
	const int args = lua_gettop(l);
	if (args < 1) {
		LuaError(l, "argument missed");
		return 1;
	}
	for (int arg = 0; arg < args; ++arg) {
		const char *flag_name = LuaToString(l, arg + 1);
		if (!strcmp(flag_name, "wall")) {
			new_flag |= MapFieldWall;
		} else if (!strcmp(flag_name, "rock")) {
			new_flag |= MapFieldRocks;
		} else if (!strcmp(flag_name, "forest")) {
			new_flag |= MapFieldForest;
		} else {
			PrintFunction();
			fprintf(stdout, "Opaque can only be set for \"wall\", \"rock\" or \"forest\". \n");
			return 1;
		}
	}
	if (!IsNetworkGame()) {
		FieldOfView.SetOpaqueFields(FieldOfView.GetOpaqueFields() | new_flag);
	} else {
		NetworkSendExtendedCommand(ExtendedMessageMapFieldsOpacityDB, 0,
								   FieldOfView.GetOpaqueFields() | new_flag, 0, 0, 0);
	}
	return 0;
}

RemoveOpaqueFor

/map/script_map.cpp:469 CclRemoveOpaqueFor

static int CclRemoveOpaqueFor(lua_State *l)
{
	unsigned short new_flag = 0;
	const int args = lua_gettop(l);
	if (args < 1) {
		LuaError(l, "argument missed");
		return 1;
	}
	for (int arg = 0; arg < args; ++arg) {
		const char *flag_name = LuaToString(l, arg + 1);
		if (!strcmp(flag_name, "wall")) {
			new_flag |= MapFieldWall;
		} else if (!strcmp(flag_name, "rock")) {
			new_flag |= MapFieldRocks;
		} else if (!strcmp(flag_name, "forest")) {
			new_flag |= MapFieldForest;
		} else {
			PrintFunction();
			fprintf(stdout, "Opaque can only be removed for \"wall\", \"rock\" or \"forest\". \n");
			return 1;
		}
	}
	if (!IsNetworkGame()) {
		FieldOfView.SetOpaqueFields(FieldOfView.GetOpaqueFields() & ~new_flag);
	} else {
		NetworkSendExtendedCommand(ExtendedMessageMapFieldsOpacityDB, 0,
								   FieldOfView.GetOpaqueFields() & ~new_flag, 0, 0, 0);
	}
	return 0;
}

GetIsOpaqueFor


Check opacity for the tile's terrain.

@param l Lua state.

/map/script_map.cpp:438 CclGetIsOpaqueFor

static int CclGetIsOpaqueFor(lua_State *l)
{
	LuaCheckArgs(l, 1);

	uint16_t flagToCheck = 0;
	const char *flag_name = LuaToString(l, 1);
	if (!strcmp(flag_name, "wall")) {
		flagToCheck = MapFieldWall;
	} else if (!strcmp(flag_name, "rock")) {
		flagToCheck = MapFieldRocks;
	} else if (!strcmp(flag_name, "forest")) {
		flagToCheck = MapFieldForest;
	} else {
		PrintFunction();
		fprintf(stdout, "Opaque can only be checked for \"wall\", \"rock\" or \"forest\". \n");
	}

	lua_pushboolean(l, FieldOfView.GetOpaqueFields() & flagToCheck);
	return 1;
}

SetFogOfWarType


Select which type of Fog of War to use

@param l Lua state.

@return 0 for success, 1 for wrong type;

/map/script_map.cpp:505 CclSetFogOfWarType

static int CclSetFogOfWarType(lua_State *l)
{
	LuaCheckArgs(l, 1);
	
	FogOfWarTypes new_type;
	const std::string type_name {LuaToString(l, 1)};
	if (type_name == "tiled" || type_name == "fast") {
		new_type = type_name == "tiled" ? FogOfWarTypes::cTiled : FogOfWarTypes::cTiledLegacy;
		/// Tiled types of FOW don't work with shadow casting
		if (FieldOfView.GetType() == FieldOfViewTypes::cShadowCasting) {
			if (!IsNetworkGame()) {
				FieldOfView.SetType(FieldOfViewTypes::cSimpleRadial);
			} else {
				NetworkSendExtendedCommand(ExtendedMessageFieldOfViewDB, 
										   int(FieldOfViewTypes::cSimpleRadial), 0, 0, 0, 0);
			}
		}
	} else if (type_name == "enhanced") {
		new_type = FogOfWarTypes::cEnhanced;
	} else {
		PrintFunction();
		fprintf(stdout, "Accessible Fog of War types: \"tiled\", \"enhanced\" and \"fast\".\n");
		return 1;
	}
	FogOfWar->SetType(new_type);
	return 0;
}

GetFogOfWarType


Get Fog of War type - legacy or enhanced

/map/script_map.cpp:515 CclGetFogOfWarType

static int CclGetFogOfWarType(lua_State *l)
{
	LuaCheckArgs(l, 0);
	lua_pushinteger(l, int(FogOfWar->GetType()));
	return 1;
}

SetFogOfWarOpacityLevels


Set opacity (alpha) for different levels of fog of war - explored, revealed, unseen

@param l Lua state.

@return 0 for success, 1 for wrong type;

/map/script_map.cpp:549 CclSetFogOfWarOpacityLevels

static int CclSetFogOfWarOpacityLevels(lua_State *l)
{
	LuaCheckArgs(l, 3);
	const int explored = LuaToNumber(l, 1);
	if (explored <= 0 || explored > 255) {
		PrintFunction();
		fprintf(stderr, "Invalid value (%d) of opacity for Explored tiles. Acceptable range is [0 <= Explored <= Known <= Hidden <= 255].\n", explored);
		return 1;
	}
	const int revealed = LuaToNumber(l, 2);
	if (revealed <= explored || revealed > 255) {
		PrintFunction();
		fprintf(stderr, "Invalid value (%d) of opacity for Revealed tiles. Acceptable range is [0 <= Explored <= Known <= Hidden <= 255].\n", revealed);
		return 1;
	}
	const int unseen = LuaToNumber(l, 3);
	if (unseen < revealed || unseen > 255) {
		PrintFunction();
		fprintf(stderr, "Invalid value (%d) of opacity for Unseen tiles. Acceptable range is [0 <= Explored <= Known <= Hidden <= 255].\n", unseen);
		return 1;
	}

	FogOfWar->SetOpacityLevels(explored, revealed, unseen);

	return 0;	
}

SetFogOfWarBlur


Set parameters for FOW blurer (radiuses and number of iterations)

@param l Lua state.

@return 0 for success, 1 for wrong type;

/map/script_map.cpp:581 CclSetFogOfWarBlur

static int CclSetFogOfWarBlur(lua_State *l)
{
	LuaCheckArgs(l, 3);

	const float radiusSimple = LuaToFloat(l, 1);
	if (radiusSimple <= 0 ) {
		PrintFunction();
		fprintf(stdout, "Radius should be a positive float number. Blur is disabled.\n");
	}

	const float radiusBilinear = LuaToFloat(l, 2);
	if (radiusBilinear <= 0 ) {
		PrintFunction();
		fprintf(stdout, "Radius should be a positive float number. Blur is disabled.\n");
	}

	const int iterations = LuaToNumber(l, 3);	
	if (iterations <= 0 ) {
		PrintFunction();
		fprintf(stdout, "Number of box blur iterations should be greater than 0. Blur is disabled.\n");
	}
	FogOfWar->InitBlurer(radiusSimple, radiusBilinear, iterations);
	return 0;
}

SetFogOfWarBilinear


Activate FOW bilinear upscaling type (true|false)

@param l Lua state.

@return 0 for success, 1 for wrong type;

/map/script_map.cpp:595 CclSetFogOfWarBilinear

static int CclSetFogOfWarBilinear(lua_State *l)
{
	LuaCheckArgs(l, 1);
	FogOfWar->EnableBilinearUpscale(LuaToBoolean(l, 1));
	return 0;
}

GetIsFogOfWarBilinear


Check if FOW bilinear upscaling enabled

/map/script_map.cpp:605 CclGetIsFogOfWarBilinear

static int CclGetIsFogOfWarBilinear(lua_State *l)
{
	LuaCheckArgs(l, 0);
	lua_pushboolean(l, FogOfWar->IsBilinearUpscaleEnabled());
	return 1;
}

SetFogOfWarGraphics


Define Fog graphics

@param l Lua state.

/map/script_map.cpp:689 CclSetFogOfWarGraphics

static int CclSetFogOfWarGraphics(lua_State *l)
{
	std::string FogGraphicFile;

	LuaCheckArgs(l, 1);
	FogGraphicFile = LuaToString(l, 1);
	CFogOfWar::SetTiledFogGraphic(FogGraphicFile);

	return 0;
}

SetFogOfWarColor


Description

Set Fog color.

@param l Lua state.

Example:

-- Red fog of war
SetFogOfWarColor(128,0,0)

/map/script_map.cpp:673 CclSetFogOfWarColor

static int CclSetFogOfWarColor(lua_State *l)
{
	LuaCheckArgs(l, 3);
	int r = LuaToNumber(l, 1);
	int g = LuaToNumber(l, 2);
	int b = LuaToNumber(l, 3);

	if ((r < 0 || r > 255) ||
		(g < 0 || g > 255) ||
		(b < 0 || b > 255)) {
		LuaError(l, "Arguments must be in the range 0-255");
	}

	FogOfWar->SetFogColor(r, g, b);

	return 0;
}

SetMMFogOfWarOpacityLevels


Set opacity (alpha) for different levels of fog of war - explored, revealed, unexplored for mini map

@param l Lua state.

@return 0 for success, 1 for wrong type;

/map/script_map.cpp:724 CclSetMMFogOfWarOpacityLevels

static int CclSetMMFogOfWarOpacityLevels(lua_State *l)
{
	LuaCheckArgs(l, 3);
	const int explored = LuaToNumber(l, 1);
	if (explored <= 0 || explored > 255) {
		PrintFunction();
		fprintf(stderr, "Invalid value (%d) of opacity for Minimap's Explored tiles. Acceptable range is [0 <= Explored <= Known <= Hidden <= 255].\n", explored);
		return 1;
	}
	const int revealed = LuaToNumber(l, 2);
	if (revealed <= explored || revealed > 255) {
		PrintFunction();
		fprintf(stderr, "Invalid value (%d) of opacity for Minimap's  Revealed tiles. Acceptable range is [0 <= Explored <= Known <= Hidden <= 255].\n", revealed);
		return 1;
	}
	const int unseen = LuaToNumber(l, 3);
	if (unseen < revealed || unseen > 255) {
		PrintFunction();
		fprintf(stderr, "Invalid value (%d) of opacity for Minimap's Unseen tiles. Acceptable range is [0 <= Explored <= Known <= Hidden <= 255].\n", unseen);
		return 1;
	}

	UI.Minimap.SetFogOpacityLevels(explored, revealed, unseen);

	return 0;	
}

SetForestRegeneration


Description

Set forest regeneration speed.

@param l Lua state.

@return Old speed

Example:

-- No regeneration.
SetForestRegeneration(0)
-- Slow regeneration every 50 seconds
SetForestRegeneration(50)
-- Extremely slow regeneration every 1h of game time
SetForestRegeneration(3600)

/map/script_map.cpp:643 CclSetForestRegeneration

static int CclSetForestRegeneration(lua_State *l)
{
	LuaCheckArgs(l, 1);
	int i = LuaToNumber(l, 1);
	int frequency = 1;
	if (i < 0) {
		LuaError(l, "Regeneration speed should be >= 0\n");
	}
	while (i / frequency > 255) {
		frequency++;
	}
	i = i / frequency;
	const int old = ForestRegeneration * ForestRegenerationFrequency;
	ForestRegeneration = i;
	ForestRegenerationFrequency = frequency;

	lua_pushnumber(l, old);
	return 1;
}

LoadTileModels


Load the lua file which will define the tile models

@param l Lua state.

/map/script_map.cpp:829 CclLoadTileModels

static int CclLoadTileModels(lua_State *l)
{
	if (lua_gettop(l) != 1) {
		LuaError(l, "incorrect argument");
	}
	Map.TileModelsFileName = LuaToString(l, 1);
	const std::string filename = LibraryFileName(Map.TileModelsFileName.c_str());
	if (LuaLoadFile(filename) == -1) {
		DebugPrint("Load failed: %s\n" _C_ filename.c_str());
	}
	return 0;
}

DefinePlayerTypes


Define the type of each player available for the map

@param l Lua state.

/map/script_map.cpp:811 CclDefinePlayerTypes

static int CclDefinePlayerTypes(lua_State *l)
{
	int numplayers = lua_gettop(l); /* Number of players == number of arguments */
	if (numplayers < 2) {
		LuaError(l, "Not enough players");
	}

	for (int i = 0; i < numplayers && i < PlayerMax; ++i) {
		if (lua_isnil(l, i + 1)) {
			numplayers = i;
			break;
		}
		const char *type = LuaToString(l, i + 1);
		if (!strcmp(type, "neutral")) {
			Map.Info.PlayerType[i] = PlayerTypes::PlayerNeutral;
		} else if (!strcmp(type, "nobody")) {
			Map.Info.PlayerType[i] = PlayerTypes::PlayerNobody;
		} else if (!strcmp(type, "computer")) {
			Map.Info.PlayerType[i] = PlayerTypes::PlayerComputer;
		} else if (!strcmp(type, "person")) {
			Map.Info.PlayerType[i] = PlayerTypes::PlayerPerson;
		} else if (!strcmp(type, "rescue-passive")) {
			Map.Info.PlayerType[i] = PlayerTypes::PlayerRescuePassive;
		} else if (!strcmp(type, "rescue-active")) {
			Map.Info.PlayerType[i] = PlayerTypes::PlayerRescueActive;
		} else {
			LuaError(l, "Unsupported tag: %s" _C_ type);
		}
	}
	for (int i = numplayers; i < PlayerMax - 1; ++i) {
		Map.Info.PlayerType[i] = PlayerTypes::PlayerNobody;
	}
	if (numplayers < PlayerMax) {
		Map.Info.PlayerType[PlayerMax - 1] = PlayerTypes::PlayerNeutral;
	}
	return 0;
}

DefineTileset


Define tileset

@param l Lua state.

/map/script_map.cpp:847 CclDefineTileset

static int CclDefineTileset(lua_State *l)
{
	Map.Tileset->parse(l);

	//  Load and prepare the tileset
	PixelTileSize = Map.Tileset->getPixelTileSize();

	ShowLoadProgress(_("Tileset '%s'"), Map.Tileset->ImageFile.c_str());
	Map.TileGraphic = CGraphic::New(Map.Tileset->ImageFile, PixelTileSize.x, PixelTileSize.y);
	Map.TileGraphic->Load();
	return 0;
}

SetTileFlags


Set the flags like "water" for a tile of a tileset

@param l Lua state.

/map/script_map.cpp:886 CclSetTileFlags

static int CclSetTileFlags(lua_State *l)
{
	if (lua_gettop(l) < 2) {
		LuaError(l, "No flags defined");
	}
	const unsigned int tilenumber = LuaToNumber(l, 1);

	if (tilenumber >= Map.Tileset->tiles.size()) {
		LuaError(l, "Accessed a tile that's not defined");
	}
	int j = 0;
	int flags = 0;

	unsigned char newBase = Map.Tileset->parseTilesetTileFlags(l, &flags, &j);
	Map.Tileset->tiles[tilenumber].flag = flags;
	if (newBase) {
		Map.Tileset->tiles[tilenumber].tileinfo.BaseTerrain = newBase;
	}
	return 0;
}

BuildTilesetTables


Build tileset tables like humanWallTable or mixedLookupTable

Called after DefineTileset and only for tilesets that have wall,
trees and rocks. This function will be deleted when removing
support of walls and alike in the tileset.

/map/script_map.cpp:861 CclBuildTilesetTables

static int CclBuildTilesetTables(lua_State *l)
{
	LuaCheckArgs(l, 0);

	Map.Tileset->buildTable(l);
	return 0;
}

GetTileTerrainName


Get the name of the terrain of the tile.

@param l Lua state.

@return The name of the terrain of the tile.

/map/script_map.cpp:909 CclGetTileTerrainName

static int CclGetTileTerrainName(lua_State *l)
{
	LuaCheckArgs(l, 2);

	const Vec2i pos(LuaToNumber(l, 1), LuaToNumber(l, 2));

	const CMapField &mf = *Map.Field(pos);
	const CTileset &tileset = *Map.Tileset;
	const int index = tileset.findTileIndexByTile(mf.getGraphicTile());
	Assert(index != -1);
	const int baseTerrainIdx = tileset.tiles[index].tileinfo.BaseTerrain;

	lua_pushstring(l, tileset.getTerrainName(baseTerrainIdx).c_str());
	return 1;
}

GetTileTerrainHasFlag


Check if the tile's terrain has a particular flag.

@param l Lua state.

@return True if has the flag, false if not.

/map/script_map.cpp:960 CclGetTileTerrainHasFlag

static int CclGetTileTerrainHasFlag(lua_State *l)
{
	LuaCheckArgs(l, 3);

	const Vec2i pos(LuaToNumber(l, 1), LuaToNumber(l, 2));
	if (pos.x >= Map.Info.MapWidth || pos.y >= Map.Info.MapHeight || pos.x < 0 || pos.y < 0) {
		// out of bounds, doesn't have it
		lua_pushboolean(l, 0);
		return 1;
	}

	unsigned short flag = 0;
	const char *flag_name = LuaToString(l, 3);
	if (!strcmp(flag_name, "opaque")) {
		flag = MapFieldOpaque;
	} else if (!strcmp(flag_name, "water")) {
		flag = MapFieldWaterAllowed;
	} else if (!strcmp(flag_name, "land")) {
		flag = MapFieldLandAllowed;
	} else if (!strcmp(flag_name, "coast")) {
		flag = MapFieldCoastAllowed;
	} else if (!strcmp(flag_name, "no-building")) {
		flag = MapFieldNoBuilding;
	} else if (!strcmp(flag_name, "unpassable")) {
		flag = MapFieldUnpassable;
	} else if (!strcmp(flag_name, "wall")) {
		flag = MapFieldWall;
	} else if (!strcmp(flag_name, "rock")) {
		flag = MapFieldRocks;
	} else if (!strcmp(flag_name, "forest")) {
		flag = MapFieldForest;
	}

	const CMapField &mf = *Map.Field(pos);

	if (mf.getFlag() & flag) {
		lua_pushboolean(l, 1);
	} else {
		lua_pushboolean(l, 0);
	}

	return 1;
}

SetEnableWallsForSP


Enable walls enabled for single player games (for debug purposes)

@param l Lua state.

@return 0 for success, 1 for wrong type;

/map/script_map.cpp:974 CclSetEnableWallsForSP

static int CclSetEnableWallsForSP(lua_State *l)
{
	LuaCheckArgs(l, 1);
	EnableWallsInSinglePlayer = LuaToBoolean(l, 1);
	return 0;
}

GetIsWallsEnabledForSP


Check if walls enabled for single player games (for debug purposes)

/map/script_map.cpp:984 CclIsWallsEnabledForSP

static int CclIsWallsEnabledForSP(lua_State *l)
{
	LuaCheckArgs(l, 0);
	lua_pushboolean(l, EnableWallsInSinglePlayer);
	return 1;
}

GetIsGameHoster


Check if network game was created on this PC

/map/script_map.cpp:994 CclGetIsGameHoster

static int CclGetIsGameHoster(lua_State *l)
{
	LuaCheckArgs(l, 0);
	lua_pushboolean(l, (ThisPlayer->Index == Hosts[0].PlyNr) ? true : false);
	return 1;
}


/stratagus/construct.cpp
DefineConstruction


Parse the construction.

@param l Lua state.

@note make this more flexible

/stratagus/construct.cpp:290 CclDefineConstruction

static int CclDefineConstruction(lua_State *l)
{
	LuaCheckArgs(l, 2);
	if (!lua_istable(l, 2)) {
		LuaError(l, "incorrect argument");
	}

	// Slot identifier
	const std::string str = LuaToString(l, 1);
	CConstruction *construction = ConstructionByIdent(str);
	std::vector<CConstruction *>::iterator i;

	if (construction == NULL) {
		construction = new CConstruction;
		Constructions.push_back(construction);
	} else { // redefine completely.
		construction->Clean();
	}
	construction->Ident = str;

	//  Parse the arguments, in tagged format.
	lua_pushnil(l);
	while (lua_next(l, 2)) {
		const char *value = LuaToString(l, -2);
		bool files = !strcmp(value, "Files");

		if (files || !strcmp(value, "ShadowFiles")) {
			std::string file;
			int w = 0;
			int h = 0;

			if (!lua_istable(l, -1)) {
				LuaError(l, "incorrect argument");
			}
			lua_pushnil(l);
			while (lua_next(l, -2)) {
				const char *value = LuaToString(l, -2);

				if (!strcmp(value, "File")) {
					file = LuaToString(l, -1);
				} else if (!strcmp(value, "Size")) {
					CclGetPos(l, &w, &h);
				} else {
					LuaError(l, "Unsupported tag: %s" _C_ value);
				}
				lua_pop(l, 1);
			}
			if (files) {
				construction->File.File = file;
				construction->File.Width = w;
				construction->File.Height = h;
			} else {
				construction->ShadowFile.File = file;
				construction->ShadowFile.Width = w;
				construction->ShadowFile.Height = h;
			}
		} else if (!strcmp(value, "Constructions")) {
			const unsigned int subargs = lua_rawlen(l, -1);

			for (unsigned int k = 0; k < subargs; ++k) {
				int percent = 0;
				ConstructionFileType file = ConstructionFileConstruction;
				int frame = 0;

				lua_rawgeti(l, -1, k + 1);
				if (!lua_istable(l, -1)) {
					LuaError(l, "incorrect argument");
				}
				lua_pushnil(l);
				while (lua_next(l, -2)) {
					const char *value = LuaToString(l, -2);

					if (!strcmp(value, "Percent")) {
						percent = LuaToNumber(l, -1);
					} else if (!strcmp(value, "File")) {
						const char *value = LuaToString(l, -1);

						if (!strcmp(value, "construction")) {
							file = ConstructionFileConstruction;
						} else if (!strcmp(value, "main")) {
							file = ConstructionFileMain;
						} else {
							LuaError(l, "Unsupported tag: %s" _C_ value);
						}
					} else if (!strcmp(value, "Frame")) {
						frame = LuaToNumber(l, -1);
					} else {
						LuaError(l, "Unsupported tag: %s" _C_ value);
					}
					lua_pop(l, 1);
				}
				lua_pop(l, 1);
				CConstructionFrame **cframe = &construction->Frames;
				while (*cframe) {
					cframe = &((*cframe)->Next);
				}
				(*cframe) = new CConstructionFrame;
				(*cframe)->Percent = percent;
				(*cframe)->File = file;
				(*cframe)->Frame = frame;
				(*cframe)->Next = NULL;
			}
		} else {
			LuaError(l, "Unsupported tag: %s" _C_ value);
		}
		lua_pop(l, 1);
	}
	return 0;
}


/stratagus/script_player.cpp
Player


Parse the player configuration.

@param l Lua state.

/stratagus/script_player.cpp:90 CclPlayer

static int CclPlayer(lua_State *l)
{
	int i = LuaToNumber(l, 1);

	CPlayer &player = Players[i];
	player.Index = i;

	if (NumPlayers <= i) {
		NumPlayers = i + 1;
	}

	player.Load(l);
	return 0;
}

ChangeUnitsOwner


Description

Change all units owned by one player or change only specific units owned by one player

@param l Lua state.

Example:

-- Changes all units owned by player 0 and give to player 1
ChangeUnitsOwner({16, 17}, {30, 32}, 0, 1)
-- Changes all farms owned by player 0 and give to player 1
ChangeUnitsOwner({16, 17}, {30, 32}, 0, 1, "unit-farm")

/stratagus/script_player.cpp:384 CclChangeUnitsOwner

static int CclChangeUnitsOwner(lua_State *l)
{
    int args = lua_gettop(l);
    if (args != 4 && args != 5) {
        LuaError(l, "incorrect argument count, need 4 or 5 args");
    }

    Vec2i pos1;
    Vec2i pos2;
    CclGetPos(l, &pos1.x, &pos1.y, 1);
    CclGetPos(l, &pos2.x, &pos2.y, 2);
	if (pos1.x > pos2.x) {
		std::swap(pos1.x, pos2.x);
	}
	if (pos1.y > pos2.y) {
		std::swap(pos1.y, pos2.y);
	}

    const int oldp = LuaToNumber(l, 3);
    const int newp = LuaToNumber(l, 4);
    std::vector<CUnit *> table;
	// Change all units
    if (args == 4) {
        Select(pos1, pos2, table, HasSamePlayerAs(Players[oldp]));
    } else { //Change only specific units by the type.
        CUnitType *type = UnitTypeByIdent(LuaToString(l, 5));
        Select(pos1, pos2, table, HasSamePlayerAndTypeAs(Players[oldp], *type));
    }
    for (auto unit : table) {
        unit->ChangeOwner(Players[newp]);
    }
    return 0;
}

GiveUnitsToPlayer


Description

GiveUnitsToPlayer(amount, type, fromPlayer, toPlayer)
GiveUnitsToPlayer(amount, type, topLeft, bottomRight, fromPlayer, toPlayer)
Give some units of a specific type from a player to another player. Optionally only inside a rectangle.
Returns number of units actually assigned. This can be smaller than the requested amount if the
fromPlayer did not have enough units.


Instead of a number you can pass "all" as the first argument, to hand over all units.


Instead of a unit type name, you can pass "any", "unit", "building" as the second argument,
to hand over anything, and unit, or any building.

@param l Lua state.

Example:


-- Give 2 peasants from player 4 to player 2
GiveUnitsToPlayer(2, "unit-peasant", 4, 2)
-- Give 4 knights from player 5 to player 1 inside the rectangle 2,2 - 14,14
GiveUnitsToPlayer(2, "unit-peasant", {2,2}, {14,14}, 4, 2)
-- Give any 4 units from player 5 to player 1 inside the rectangle 2,2 - 14,14
GiveUnitsToPlayer(2, "any", 4, 2)

/stratagus/script_player.cpp:496 CclGiveUnitsToPlayer

static int CclGiveUnitsToPlayer(lua_State *l)
{
	int args = lua_gettop(l);
	if (args != 4 && args != 6) {
		LuaError(l, "incorrect argument count for GiveUnitsToPlayer, need 4 or 6 args");
	}

	int cnt;
	if (lua_isnumber(l, 1)) {
		cnt = LuaToNumber(l, 1);
	} else {
		std::string cntStr = std::string(LuaToString(l, 1));
		if (cntStr != "all") {
			LuaError(l, "incorrect 1st argument to GiveUnitsToPlayer. Must be number or 'all'");
		}
		cnt = std::numeric_limits<int>::max();
	}

	const int oldp = LuaToNumber(l, args == 4 ? 3 : 5);
	const int newp = LuaToNumber(l, args == 4 ? 4 : 6);

	std::string typestr = std::string(LuaToString(l, 2));
	int assignedCnt = 0;

	CUnitType *type = nullptr;
	bool any = false;
	bool onlyUnits = false;
	bool onlyBuildings = false;
	if ((any = (typestr == "any"))) {
	} else if ((onlyUnits = (typestr == "unit"))) {
	} else if ((onlyBuildings = (typestr == "building"))) {
	} else {
		type = UnitTypeByIdent(LuaToString(l, 2));
		if (!type) {
			LuaError(l, "incorrect 2nd argument to GiveUnitsToPlayer. Must be a unit type or 'any', 'unit', or 'building'");
		}
	}

	if (cnt > 0) {
		std::vector<CUnit *> table;
		if (args == 6) {
			Vec2i pos1;
			Vec2i pos2;
			CclGetPos(l, &pos1.x, &pos1.y, 3);
			CclGetPos(l, &pos2.x, &pos2.y, 4);
			if (pos1.x > pos2.x) {
				std::swap(pos1.x, pos2.x);
			}
			if (pos1.y > pos2.y) {
				std::swap(pos1.y, pos2.y);
			}
			if (any) {
				Select(pos1, pos2, table, HasSamePlayerAs(Players[oldp]));
			} else if (onlyUnits) {
				Select(pos1, pos2, table, AndPredicate(HasSamePlayerAs(Players[oldp]), NotPredicate(IsBuildingType())));
			} else if (onlyBuildings) {
				Select(pos1, pos2, table, AndPredicate(HasSamePlayerAs(Players[oldp]), IsBuildingType()));
			} else {
				Select(pos1, pos2, table, HasSamePlayerAndTypeAs(Players[oldp], *type));
			}
			for (size_t i = 0; i != table.size() && cnt > 0; ++i) {
				table[i]->ChangeOwner(Players[newp]);
				assignedCnt++;
				cnt--;
			}
		} else {
			std::vector<CUnit *> table;
			for (std::vector<CUnit *>::const_iterator it = Players[oldp].UnitBegin(); it != Players[oldp].UnitEnd() && cnt > 0; ++it) {
				CUnit *unit = *it;
				if (any || (onlyUnits && !unit->Type->Building) || (onlyBuildings && unit->Type->Building) || (type == unit->Type)) {
					table.push_back(unit);
				}
			}
			for (auto unit : table) {
				unit->ChangeOwner(Players[newp]);
			}
			assignedCnt = table.size();
		}
	}

	lua_pushnumber(l, assignedCnt);
	return 1;
}

GetThisPlayer


Description

Get ThisPlayer.

@param l Lua state.

Example:

GetThisPlayer()

/stratagus/script_player.cpp:518 CclGetThisPlayer

static int CclGetThisPlayer(lua_State *l)
{
	LuaCheckArgs(l, 0);
	if (ThisPlayer) {
		lua_pushnumber(l, ThisPlayer - Players);
	} else {
		lua_pushnumber(l, 0);
	}
	return 1;
}

SetThisPlayer


Description

Set ThisPlayer.

@param l Lua state.

/stratagus/script_player.cpp:535 CclSetThisPlayer

static int CclSetThisPlayer(lua_State *l)
{
	LuaCheckArgs(l, 1);
	int plynr = LuaToNumber(l, 1);
	ThisPlayer = &Players[plynr];

	lua_pushnumber(l, plynr);
	return 1;
}

SetMaxSelectable


Description

Set the maximum amount of units that can be selected.

@param l Lua state.

Example:

-- 9 units can be selected together.
SetMaxSelectable(9)
-- 18 units can be selected together.
SetMaxSelectable(18)
-- 50 units can be selected together.
SetMaxSelectable(50)

/stratagus/script_player.cpp:560 CclSetMaxSelectable

static int CclSetMaxSelectable(lua_State *l)
{
	LuaCheckArgs(l, 1);
	MaxSelectable = LuaToNumber(l, 1);

	lua_pushnumber(l, MaxSelectable);
	return 1;
}

SetAllPlayersUnitLimit


Description

Set players units limit.

@param l Lua state.

Example:

SetAllPlayersUnitLimit(200)

/stratagus/script_player.cpp:582 CclSetAllPlayersUnitLimit

static int CclSetAllPlayersUnitLimit(lua_State *l)
{
	LuaCheckArgs(l, 1);
	for (int i = 0; i < PlayerMax; ++i) {
		Players[i].UnitLimit = LuaToNumber(l, 1);
	}

	lua_pushnumber(l, lua_tonumber(l, 1));
	return 1;
}

SetAllPlayersBuildingLimit


Description

Set players buildings limit.

@param l Lua state.

Example:

SetAllPlayersBuildingLimit(200)

/stratagus/script_player.cpp:604 CclSetAllPlayersBuildingLimit

static int CclSetAllPlayersBuildingLimit(lua_State *l)
{
	LuaCheckArgs(l, 1);
	for (int i = 0; i < PlayerMax; ++i) {
		Players[i].BuildingLimit = LuaToNumber(l, 1);
	}

	lua_pushnumber(l, lua_tonumber(l, 1));
	return 1;
}

SetAllPlayersTotalUnitLimit


Description

Set players total units limit.

@param l Lua state.

Example:

SetAllPlayersTotalUnitLimit(400)

/stratagus/script_player.cpp:626 CclSetAllPlayersTotalUnitLimit

static int CclSetAllPlayersTotalUnitLimit(lua_State *l)
{
	LuaCheckArgs(l, 1);
	for (int i = 0; i < PlayerMax; ++i) {
		Players[i].TotalUnitLimit = LuaToNumber(l, 1);
	}

	lua_pushnumber(l, lua_tonumber(l, 1));
	return 1;
}

SetDiplomacy


Description

Change the diplomacy from player to another player.

@param l Lua state.

@return FIXME: should return old state.

Example:

SetDiplomacy(0,"allied",1)
SetDiplomacy(1,"allied",0)

SetDiplomacy(0,"enemy",2)
SetDiplomacy(1,"enemy",2)

/stratagus/script_player.cpp:662 CclSetDiplomacy

static int CclSetDiplomacy(lua_State *l)
{
	LuaCheckArgs(l, 3);
	const int base = LuaToNumber(l, 1);
	const int plynr = LuaToNumber(l, 3);
	const char *state = LuaToString(l, 2);

	if (!strcmp(state, "allied")) {
		SendCommandDiplomacy(base, DiplomacyAllied, plynr);
	} else if (!strcmp(state, "neutral")) {
		SendCommandDiplomacy(base, DiplomacyNeutral, plynr);
	} else if (!strcmp(state, "crazy")) {
		SendCommandDiplomacy(base, DiplomacyCrazy, plynr);
	} else if (!strcmp(state, "enemy")) {
		SendCommandDiplomacy(base, DiplomacyEnemy, plynr);
	}
	return 0;
}

GetDiplomacy


Get diplomacy from one player to another. Returns the strings "allied",
"enemy", "neutral", or "crazy".

/stratagus/script_player.cpp:698 CclGetDiplomacy

static int CclGetDiplomacy(lua_State *l)
{
	LuaCheckArgs(l, 2);
	const int base = LuaToNumber(l, 1);
	const int plynr = LuaToNumber(l, 2);

	if (Players[base].IsEnemy(plynr)) {
		if (Players[base].IsAllied(plynr)) {
			lua_pushstring(l, "crazy");
		} else {
			lua_pushstring(l, "enemy");
		}
	} else if (Players[base].IsAllied(plynr)) {
		lua_pushstring(l, "allied");
	} else {
		lua_pushstring(l, "neutral");
	}
	return 1;
}

Diplomacy


Change the diplomacy from ThisPlayer to another player.

@param l Lua state.

/stratagus/script_player.cpp:674 CclDiplomacy

static int CclDiplomacy(lua_State *l)
{
	lua_pushnumber(l, ThisPlayer->Index);
	lua_insert(l, 1);
	return CclSetDiplomacy(l);
}

SetSharedVision


Description

Change the shared vision from player to another player.


@param l Lua state.

@return FIXME: should return old state.

Example:

SetSharedVision(0,true,1)
SetSharedVision(1,true,0)

SetSharedVision(0,false,2)
SetSharedVision(1,false,2)

/stratagus/script_player.cpp:729 CclSetSharedVision

static int CclSetSharedVision(lua_State *l)
{
	LuaCheckArgs(l, 3);

	const int base = LuaToNumber(l, 1);
	const bool shared = LuaToBoolean(l, 2);
	const int plynr = LuaToNumber(l, 3);

	SendCommandSharedVision(base, shared, plynr);

	return 0;
}

SharedVision


Change the shared vision from ThisPlayer to another player.

@param l Lua state.

/stratagus/script_player.cpp:741 CclSharedVision

static int CclSharedVision(lua_State *l)
{
	lua_pushnumber(l, ThisPlayer->Index);
	lua_insert(l, 1);
	return CclSetSharedVision(l);
}

SetRevelationType


Description

Change the players revelation type - reveal all units, only buidings or don't reveal anything

@param l Lua state.

Example:

SetRevelationType("no-revelation")
SetRevelationType("buildings-only")
SetRevelationType("all-units")

/stratagus/script_player.cpp:774 CclSetRevelationType

static int CclSetRevelationType(lua_State *l)
{
	LuaCheckArgs(l, 1);

	const char *revel_type = LuaToString(l, 1);
	if (!strcmp(revel_type, "no-revelation")) {
		CPlayer::SetRevelationType(RevealTypes::cNoRevelation);
	} else if (!strcmp(revel_type, "all-units")) {
		CPlayer::SetRevelationType(RevealTypes::cAllUnits);
	} else if (!strcmp(revel_type, "buildings-only")) {
		CPlayer::SetRevelationType(RevealTypes::cBuildingsOnly);
	} else {
		PrintFunction();
		fprintf(stdout, "Accessible types of revelation \"no-revelation\", \"all-units\" and \"buildings-only\".\n");
		return 1;
	}
	return 0;
}

DefineRaceNames


Define race names

@param l Lua state.

/stratagus/script_player.cpp:825 CclDefineRaceNames

static int CclDefineRaceNames(lua_State *l)
{
	PlayerRaces.Clean();
	return CclDefineNewRaceNames(l);
}

DefineNewRaceNames


Define race names

@param l Lua state.

/stratagus/script_player.cpp:825 CclDefineRaceNames

static int CclDefineRaceNames(lua_State *l)
{
	PlayerRaces.Clean();
	return CclDefineNewRaceNames(l);
}

DefinePlayerColors


Description

Define player colors. Pass "false" as an optional second
argument to add the colors to the existing ones.

@param l Lua state.

Example:

DefinePlayerColors({
"red", {{164, 0, 0}, {124, 0, 0}, {92, 4, 0}, {68, 4, 0}},
"blue", {{12, 72, 204}, {4, 40, 160}, {0, 20, 116}, {0, 4, 76}},
"green", {{44, 180, 148}, {20, 132, 92}, {4, 84, 44}, {0, 40, 12}},
"violet", {{152, 72, 176}, {116, 44, 132}, {80, 24, 88}, {44, 8, 44}},
"orange", {{248, 140, 20}, {200, 96, 16}, {152, 60, 16}, {108, 32, 12}},
"black", {{40, 40, 60}, {28, 28, 44}, {20, 20, 32}, {12, 12, 20}},
"white", {{224, 224, 224}, {152, 152, 180}, {84, 84, 128}, {36, 40, 76}},
"yellow", {{252, 252, 72}, {228, 204, 40}, {204, 160, 16}, {180, 116, 0}},
"red", {{164, 0, 0}, {124, 0, 0}, {92, 4, 0}, {68, 4, 0}},
"blue", {{12, 72, 204}, {4, 40, 160}, {0, 20, 116}, {0, 4, 76}},
"green", {{44, 180, 148}, {20, 132, 92}, {4, 84, 44}, {0, 40, 12}},
"violet", {{152, 72, 176}, {116, 44, 132}, {80, 24, 88}, {44, 8, 44}},
"orange", {{248, 140, 20}, {200, 96, 16}, {152, 60, 16}, {108, 32, 12}},
"black", {{40, 40, 60}, {28, 28, 44}, {20, 20, 32}, {12, 12, 20}},
"white", {{224, 224, 224}, {152, 152, 180}, {84, 84, 128}, {36, 40, 76}},
"yellow", {{252, 252, 72}, {228, 204, 40}, {204, 160, 16}, {180, 116, 0}},
})

/stratagus/script_player.cpp:914 CclDefinePlayerColors

static int CclDefinePlayerColors(lua_State *l)
{
	int nargs = lua_gettop(l);
	if (nargs < 1 || nargs > 2) {
		LuaError(l, "wrong number of arguments");
	}
	if (!lua_istable(l, 1)) {
		LuaError(l, "incorrect argument");
	}
	bool defaultNeutralPlayer = false;
	const int args = lua_rawlen(l, 1);
	if (nargs < 2 || LuaToBoolean(l, 2)) {
		PlayerColorNames.clear();
		PlayerColorsRGB.clear();
		PlayerColorsSDL.clear();
		if (args / 2 < PlayerMax - 1) { // accept no color for neutral player
			LuaError(l, "You need to define at least %d colors" _C_ PlayerMax - 1);
		}
		if (args / 2 < PlayerMax) {
			defaultNeutralPlayer = true;
		}
	}

	for (int i = 0; i < args; ++i) {
		PlayerColorNames.push_back(LuaToString(l, 1, i + 1));
		++i;
		lua_rawgeti(l, 1, i + 1);
		if (!lua_istable(l, -1)) {
			LuaError(l, "incorrect argument");
		}
		const int numcolors = lua_rawlen(l, -1);
		if (numcolors != PlayerColorIndexCount) {
			LuaError(l, "You should use %d colors (See DefinePlayerColorIndex())" _C_ PlayerColorIndexCount);
		}
		std::vector<CColor> newColors;
		for (int j = 0; j < numcolors; ++j) {
			lua_rawgeti(l, -1, j + 1);
			CColor newColor;
			newColor.Parse(l);
			newColors.push_back(newColor);
			lua_pop(l, 1);
		}
		PlayerColorsRGB.push_back(newColors);
		PlayerColorsSDL.push_back(std::vector<SDL_Color>(newColors.begin(), newColors.end()));
	}

	if (defaultNeutralPlayer) {
		PlayerColorNames.push_back("neutral-black");
		std::vector<CColor> neutralColors;
		for (int j = 0; j < PlayerColorIndexCount; ++j) {
			CColor neutralColor;
			neutralColors.push_back(neutralColor);
		}
		PlayerColorsRGB.push_back(neutralColors);
		PlayerColorsSDL.push_back(std::vector<SDL_Color>(neutralColors.begin(), neutralColors.end()));
	}

	return 0;
} 

DefinePlayerColorIndex


Define player color indexes

@param l Lua state.

/stratagus/script_player.cpp:943 CclDefinePlayerColorIndex

static int CclDefinePlayerColorIndex(lua_State *l)
{
	LuaCheckArgs(l, 2);
	PlayerColorIndexStart = LuaToNumber(l, 1);
	PlayerColorIndexCount = LuaToNumber(l, 2);

	PlayerColorsRGB.clear();
	PlayerColorsSDL.clear();
	return 0;
}

NewColors


Make new player colors

@param l Lua state.

/stratagus/script_player.cpp:927 CclNewPlayerColors

static int CclNewPlayerColors(lua_State *l)
{
	LuaCheckArgs(l, 0);
	SetPlayersPalette();

	return 0;
}

GetPlayerData


Description

Get player data.

@param l Lua state.

Example:

GetPlayerData(0,"TotalNumUnits")

/stratagus/script_player.cpp:1106 CclGetPlayerData

static int CclGetPlayerData(lua_State *l)
{
	if (lua_gettop(l) < 2) {
		LuaError(l, "incorrect argument");
	}
	lua_pushvalue(l, 1);
	const CPlayer *p = CclGetPlayer(l);
	lua_pop(l, 1);
	const char *data = LuaToString(l, 2);

	if (!strcmp(data, "Name")) {
		lua_pushstring(l, p->Name.c_str());
		return 1;
	} else if (!strcmp(data, "RaceName")) {
		lua_pushstring(l, PlayerRaces.Name[p->Race].c_str());
		return 1;
	} else if (!strcmp(data, "Resources")) {
		LuaCheckArgs(l, 3);

		const std::string res = LuaToString(l, 3);
		const int resId = GetResourceIdByName(l, res.c_str());
		lua_pushnumber(l, p->Resources[resId] + p->StoredResources[resId]);
		return 1;
	} else if (!strcmp(data, "StoredResources")) {
		LuaCheckArgs(l, 3);

		const std::string res = LuaToString(l, 3);
		const int resId = GetResourceIdByName(l, res.c_str());
		lua_pushnumber(l, p->StoredResources[resId]);
		return 1;
	} else if (!strcmp(data, "MaxResources")) {
		LuaCheckArgs(l, 3);

		const std::string res = LuaToString(l, 3);
		const int resId = GetResourceIdByName(l, res.c_str());
		lua_pushnumber(l, p->MaxResources[resId]);
		return 1;
	} else if (!strcmp(data, "UnitTypesCount")) {
		LuaCheckArgs(l, 3);
		CUnitType *type = CclGetUnitType(l);
		Assert(type);
		lua_pushnumber(l, p->UnitTypesCount[type->Slot]);
		return 1;
	} else if (!strcmp(data, "UnitTypesAiActiveCount")) {
		LuaCheckArgs(l, 3);
		CUnitType *type = CclGetUnitType(l);
		Assert(type);
		lua_pushnumber(l, p->UnitTypesAiActiveCount[type->Slot]);
		return 1;
	} else if (!strcmp(data, "AiEnabled")) {
		lua_pushboolean(l, p->AiEnabled);
		return 1;
	} else if (!strcmp(data, "TotalNumUnits")) {
		lua_pushnumber(l, p->GetUnitCount());
		return 1;
	} else if (!strcmp(data, "NumBuildings")) {
		lua_pushnumber(l, p->NumBuildings);
		return 1;
	} else if (!strcmp(data, "Supply")) {
		lua_pushnumber(l, p->Supply);
		return 1;
	} else if (!strcmp(data, "Demand")) {
		lua_pushnumber(l, p->Demand);
		return 1;
	} else if (!strcmp(data, "UnitLimit")) {
		lua_pushnumber(l, p->UnitLimit);
		return 1;
	} else if (!strcmp(data, "BuildingLimit")) {
		lua_pushnumber(l, p->BuildingLimit);
		return 1;
	} else if (!strcmp(data, "TotalUnitLimit")) {
		lua_pushnumber(l, p->TotalUnitLimit);
		return 1;
	} else if (!strcmp(data, "Score")) {
		lua_pushnumber(l, p->Score);
		return 1;
	} else if (!strcmp(data, "TotalUnits")) {
		lua_pushnumber(l, p->TotalUnits);
		return 1;
	} else if (!strcmp(data, "TotalBuildings")) {
		lua_pushnumber(l, p->TotalBuildings);
		return 1;
	} else if (!strcmp(data, "TotalResources")) {
		LuaCheckArgs(l, 3);

		const std::string res = LuaToString(l, 3);
		const int resId = GetResourceIdByName(l, res.c_str());
		lua_pushnumber(l, p->TotalResources[resId]);
		return 1;
	} else if (!strcmp(data, "TotalRazings")) {
		lua_pushnumber(l, p->TotalRazings);
		return 1;
	} else if (!strcmp(data, "TotalKills")) {
		lua_pushnumber(l, p->TotalKills);
		return 1;
	} else if (!strcmp(data, "SpeedResourcesHarvest")) {
		LuaCheckArgs(l, 3);

		const std::string res = LuaToString(l, 3);
		const int resId = GetResourceIdByName(l, res.c_str());
		lua_pushnumber(l, p->SpeedResourcesHarvest[resId]);
		return 1;
	} else if (!strcmp(data, "SpeedResourcesReturn")) {
		LuaCheckArgs(l, 3);

		const std::string res = LuaToString(l, 3);
		const int resId = GetResourceIdByName(l, res.c_str());
		lua_pushnumber(l, p->SpeedResourcesReturn[resId]);
		return 1;
	} else if (!strcmp(data, "SpeedBuild")) {
		lua_pushnumber(l, p->SpeedBuild);
		return 1;
	} else if (!strcmp(data, "SpeedTrain")) {
		lua_pushnumber(l, p->SpeedTrain);
		return 1;
	} else if (!strcmp(data, "SpeedUpgrade")) {
		lua_pushnumber(l, p->SpeedUpgrade);
		return 1;
	} else if (!strcmp(data, "SpeedResearch")) {
		lua_pushnumber(l, p->SpeedResearch);
		return 1;
	} else if (!strcmp(data, "Allow")) {
		LuaCheckArgs(l, 3);
		const char *ident = LuaToString(l, 3);
		if (!strncmp(ident, "unit-", 5)) {
			int id = UnitTypeIdByIdent(ident);
			if (UnitIdAllowed(Players[p->Index], id) > 0) {
				lua_pushstring(l, "A");
			} else if (UnitIdAllowed(Players[p->Index], id) == 0) {
				lua_pushstring(l, "F");
			}
		} else if (!strncmp(ident, "upgrade-", 8)) {
			if (UpgradeIdentAllowed(Players[p->Index], ident) == 'A') {
				lua_pushstring(l, "A");
			} else if (UpgradeIdentAllowed(Players[p->Index], ident) == 'R') {
				lua_pushstring(l, "R");
			} else if (UpgradeIdentAllowed(Players[p->Index], ident) == 'F') {
				lua_pushstring(l, "F");
			}
		} else {
			DebugPrint(" wrong ident %s\n" _C_ ident);
		}
		return 1;
	} else {
		LuaError(l, "Invalid field: %s" _C_ data);
	}

	return 0;
}

SetPlayerData


Description

Set player data.

@param l Lua state.

Example:


SetPlayerData(0,"Name","Nation of Stromgarde") -- set the name of this player
SetPlayerData(0,"RaceName","human") -- the the race to human
SetPlayerData(0,"Resources","gold",1700) -- set the player to have 1700 gold
SetPlayerData(0, "Allow", "upgrade-paladin", "R") -- give the player the Paladin upgrade

/stratagus/script_player.cpp:1225 CclSetPlayerData

static int CclSetPlayerData(lua_State *l)
{
	if (lua_gettop(l) < 3) {
		LuaError(l, "incorrect argument");
	}
	lua_pushvalue(l, 1);
	CPlayer *p = CclGetPlayer(l);
	lua_pop(l, 1);
	const char *data = LuaToString(l, 2);

	if (!strcmp(data, "Name")) {
		p->SetName(LuaToString(l, 3));
	} else if (!strcmp(data, "RaceName")) {
		const char *racename = LuaToString(l, 3);
		p->Race = PlayerRaces.GetRaceIndexByName(racename);

		if (p->Race == -1) {
			LuaError(l, "invalid race name '%s'" _C_ racename);
		}
	} else if (!strcmp(data, "Resources")) {
		LuaCheckArgs(l, 4);

		const std::string res = LuaToString(l, 3);
		const int resId = GetResourceIdByName(l, res.c_str());
		p->SetResource(resId, LuaToNumber(l, 4));
	} else if (!strcmp(data, "StoredResources")) {
		LuaCheckArgs(l, 4);

		const std::string res = LuaToString(l, 3);
		const int resId = GetResourceIdByName(l, res.c_str());
		p->SetResource(resId, LuaToNumber(l, 4), STORE_BUILDING);
		// } else if (!strcmp(data, "UnitTypesCount")) {
		// } else if (!strcmp(data, "AiEnabled")) {
		// } else if (!strcmp(data, "TotalNumUnits")) {
		// } else if (!strcmp(data, "NumBuildings")) {
		// } else if (!strcmp(data, "Supply")) {
		// } else if (!strcmp(data, "Demand")) {
	} else if (!strcmp(data, "UnitLimit")) {
		p->UnitLimit = LuaToNumber(l, 3);
	} else if (!strcmp(data, "BuildingLimit")) {
		p->BuildingLimit = LuaToNumber(l, 3);
	} else if (!strcmp(data, "TotalUnitLimit")) {
		p->TotalUnitLimit = LuaToNumber(l, 3);
	} else if (!strcmp(data, "Score")) {
		p->Score = LuaToNumber(l, 3);
	} else if (!strcmp(data, "TotalUnits")) {
		p->TotalUnits = LuaToNumber(l, 3);
	} else if (!strcmp(data, "TotalBuildings")) {
		p->TotalBuildings = LuaToNumber(l, 3);
	} else if (!strcmp(data, "TotalResources")) {
		LuaCheckArgs(l, 4);

		const std::string res = LuaToString(l, 3);
		const int resId = GetResourceIdByName(l, res.c_str());
		p->TotalResources[resId] = LuaToNumber(l, 4);
	} else if (!strcmp(data, "TotalRazings")) {
		p->TotalRazings = LuaToNumber(l, 3);
	} else if (!strcmp(data, "TotalKills")) {
		p->TotalKills = LuaToNumber(l, 3);
	} else if (!strcmp(data, "SpeedResourcesHarvest")) {
		LuaCheckArgs(l, 4);

		const std::string res = LuaToString(l, 3);
		const int resId = GetResourceIdByName(l, res.c_str());
		p->SpeedResourcesHarvest[resId] = LuaToNumber(l, 4);
	} else if (!strcmp(data, "SpeedResourcesReturn")) {
		LuaCheckArgs(l, 4);

		const std::string res = LuaToString(l, 3);
		const int resId = GetResourceIdByName(l, res.c_str());
		p->SpeedResourcesReturn[resId] = LuaToNumber(l, 4);
	} else if (!strcmp(data, "SpeedBuild")) {
		p->SpeedBuild = LuaToNumber(l, 3);
	} else if (!strcmp(data, "SpeedTrain")) {
		p->SpeedTrain = LuaToNumber(l, 3);
	} else if (!strcmp(data, "SpeedUpgrade")) {
		p->SpeedUpgrade = LuaToNumber(l, 3);
	} else if (!strcmp(data, "SpeedResearch")) {
		p->SpeedResearch = LuaToNumber(l, 3);
	} else if (!strcmp(data, "Allow")) {
		LuaCheckArgs(l, 4);
		const char *ident = LuaToString(l, 3);
		const std::string acquire = LuaToString(l, 4);

		if (!strncmp(ident, "upgrade-", 8)) {
			if (acquire == "R" && UpgradeIdentAllowed(*p, ident) != 'R') {
				UpgradeAcquire(*p, CUpgrade::Get(ident));
			} else if (acquire == "F" || acquire == "A") {
				if (UpgradeIdentAllowed(*p, ident) == 'R') {
					UpgradeLost(*p, CUpgrade::Get(ident)->ID);
				}
				AllowUpgradeId(*p, UpgradeIdByIdent(ident), acquire[0]);
			}
		} else {
			LuaError(l, " wrong ident %s\n" _C_ ident);
		}
	} else {
		LuaError(l, "Invalid field: %s" _C_ data);
	}

	return 0;
}

SetAiType


Description

Set ai player algo.

@param l Lua state.

Example:

-- Player 1 has a passive A.I
SetAiType(1, "Passive")

/stratagus/script_player.cpp:1253 CclSetAiType

static int CclSetAiType(lua_State *l)
{
	CPlayer *p;

	if (lua_gettop(l) < 2) {
		LuaError(l, "incorrect argument");
	}
	lua_pushvalue(l, 1);
	p = CclGetPlayer(l);
	lua_pop(l, 1);

	p->AiName = LuaToString(l, 2);

	return 0;
}


/stratagus/selection.cpp
SetGroupId


Set the current group id. (Needed for load/save)

@param l Lua state.

/stratagus/selection.cpp:1120 CclSetGroupId

static int CclSetGroupId(lua_State *l)
{
	int old;

	LuaCheckArgs(l, 1);
	old = GroupId;
	GroupId = LuaToNumber(l, 1);

	lua_pushnumber(l, old);
	return 1;
}

Selection


Define the current selection.

@param l Lua state.

/stratagus/selection.cpp:1140 CclSelection

static int CclSelection(lua_State *l)
{
	LuaCheckArgs(l, 2);
	if (!lua_istable(l, 2)) {
		LuaError(l, "incorrect argument");
	}
	//NumSelected = LuaToNumber(l, 1);
	const int args = lua_rawlen(l, 2);
	for (int j = 0; j < args; ++j) {
		const char *str = LuaToString(l, 2, j + 1);
		Selected.push_back(&UnitManager->GetSlotUnit(strtol(str + 1, NULL, 16)));
	}
	return 0;
}


/stratagus/groups.cpp
Group


Define the group.

@param l Lua state.

/stratagus/groups.cpp:265 CclGroup

static int CclGroup(lua_State *l)
{
	LuaCheckArgs(l, 3);

	const int grpNum = LuaToNumber(l, 1);
	if (NUM_GROUPS <= grpNum) {
		LuaError(l, "grpIndex out of bound");
	}
	CUnitGroup &grp = Groups[grpNum];
	grp.init();
	//grp.Units.size() = LuaToNumber(l, 2);
	const int args = lua_rawlen(l, 3);
	for (int j = 0; j < args; ++j) {
		const char *str = LuaToString(l, 3, j + 1);
		grp.add(UnitManager->GetSlotUnit(strtol(str + 1, NULL, 16)), grpNum);
	}
	return 0;
}


/stratagus/script.cpp
Add


Return equivalent lua table for add.
{"Add", {arg1, arg2}}

@param l Lua state.

@return equivalent lua table.

/stratagus/script.cpp:1592 CclAdd

static int CclAdd(lua_State *l)
{
	LuaCheckArgs(l, 2);
	return Alias(l, "Add");
}

Sub


Return equivalent lua table for add.
{"Div", {arg1, arg2}}

@param l Lua state.

@return equivalent lua table.

/stratagus/script.cpp:1606 CclSub

static int CclSub(lua_State *l)
{
	LuaCheckArgs(l, 2);
	return Alias(l, "Sub");
}

Mul


Return equivalent lua table for add.
{"Mul", {arg1, arg2}}

@param l Lua state.

@return equivalent lua table.

/stratagus/script.cpp:1619 CclMul

static int CclMul(lua_State *l)
{
	LuaCheckArgs(l, 2);
	return Alias(l, "Mul");
}

Div


Return equivalent lua table for add.
{"Div", {arg1, arg2}}

@param l Lua state.

@return equivalent lua table.

/stratagus/script.cpp:1632 CclDiv

static int CclDiv(lua_State *l)
{
	LuaCheckArgs(l, 2);
	return Alias(l, "Div");
}

Min


Return equivalent lua table for add.
{"Min", {arg1, arg2}}

@param l Lua state.

@return equivalent lua table.

/stratagus/script.cpp:1645 CclMin

static int CclMin(lua_State *l)
{
	LuaCheckArgs(l, 2);
	return Alias(l, "Min");
}

Max


Return equivalent lua table for add.
{"Max", {arg1, arg2, argn}}

@param l Lua state.

@return equivalent lua table.

/stratagus/script.cpp:1658 CclMax

static int CclMax(lua_State *l)
{
	LuaCheckArgs(l, 2);
	return Alias(l, "Max");
}

Rand


Return equivalent lua table for add.
{"Rand", {arg1}}

@param l Lua state.

@return equivalent lua table.

/stratagus/script.cpp:1671 CclRand

static int CclRand(lua_State *l)
{
	LuaCheckArgs(l, 1);
	return Alias(l, "Rand");
}

GreaterThan


Return equivalent lua table for GreaterThan.
{"GreaterThan", {arg1, arg2}}

@param l Lua state.

@return equivalent lua table.

/stratagus/script.cpp:1684 CclGreaterThan

static int CclGreaterThan(lua_State *l)
{
	LuaCheckArgs(l, 2);
	return Alias(l, "GreaterThan");
}

LessThan


Return equivalent lua table for LessThan.
{"LessThan", {arg1, arg2}}

@param l Lua state.

@return equivalent lua table.

/stratagus/script.cpp:1710 CclLessThan

static int CclLessThan(lua_State *l)
{
	LuaCheckArgs(l, 2);
	return Alias(l, "LessThan");
}

Equal


Return equivalent lua table for Equal.
{"Equal", {arg1, arg2}}

@param l Lua state.

@return equivalent lua table.

/stratagus/script.cpp:1736 CclEqual

static int CclEqual(lua_State *l)
{
	LuaCheckArgs(l, 2);
	return Alias(l, "Equal");
}

GreaterThanOrEq


Return equivalent lua table for GreaterThanOrEq.
{"GreaterThanOrEq", {arg1, arg2}}

@param l Lua state.

@return equivalent lua table.

/stratagus/script.cpp:1697 CclGreaterThanOrEq

static int CclGreaterThanOrEq(lua_State *l)
{
	LuaCheckArgs(l, 2);
	return Alias(l, "GreaterThanOrEq");
}

LessThanOrEq


Return equivalent lua table for LessThanOrEq.
{"LessThanOrEq", {arg1, arg2}}

@param l Lua state.

@return equivalent lua table.

/stratagus/script.cpp:1723 CclLessThanOrEq

static int CclLessThanOrEq(lua_State *l)
{
	LuaCheckArgs(l, 2);
	return Alias(l, "LessThanOrEq");
}

NotEqual


Return equivalent lua table for NotEqual.
{"NotEqual", {arg1, arg2}}

@param l Lua state.

@return equivalent lua table.

/stratagus/script.cpp:1749 CclNotEqual

static int CclNotEqual(lua_State *l)
{
	LuaCheckArgs(l, 2);
	return Alias(l, "NotEqual");
}

VideoTextLength


Return equivalent lua table for VideoTextLength.
{"VideoTextLength", {Text = arg1, Font = arg2}}

@param l Lua state.

@return equivalent lua table.

/stratagus/script.cpp:1901 CclVideoTextLength

static int CclVideoTextLength(lua_State *l)
{
	LuaCheckArgs(l, 2);
	lua_newtable(l);
	lua_pushnumber(l, 1);
	lua_pushstring(l, "VideoTextLength");
	lua_rawset(l, -3);
	lua_pushnumber(l, 2);

	lua_newtable(l);
	lua_pushstring(l, "Font");
	lua_pushvalue(l, 1);
	lua_rawset(l, -3);
	lua_pushstring(l, "Text");
	lua_pushvalue(l, 2);
	lua_rawset(l, -3);

	lua_rawset(l, -3);
	return 1;
}

StringFind


Return equivalent lua table for StringFind.
{"StringFind", {arg1, arg2}}

@param l Lua state.

@return equivalent lua table.

/stratagus/script.cpp:1915 CclStringFind

static int CclStringFind(lua_State *l)
{
	LuaCheckArgs(l, 2);
	return Alias(l, "StringFind");
}

AttackerVar


Return equivalent lua table for .
{"Unit", {Unit = "Attacker", Variable = arg1, Component = "Value" or arg2}}

@param l Lua state.

@return equivalent lua table.

/stratagus/script.cpp:1498 CclUnitAttackerVar

static int CclUnitAttackerVar(lua_State *l)
{
	if (lua_gettop(l) == 0 || lua_gettop(l) > 3) {
		LuaError(l, "Bad number of arg for AttackerVar()\n");
	}
	return AliasUnitVar(l, "Attacker");
}

DefenderVar


Return equivalent lua table for .
{"Unit", {Unit = "Defender", Variable = arg1, Component = "Value" or arg2}}

@param l Lua state.

@return equivalent lua table.

/stratagus/script.cpp:1514 CclUnitDefenderVar

static int CclUnitDefenderVar(lua_State *l)
{
	if (lua_gettop(l) == 0 || lua_gettop(l) > 3) {
		LuaError(l, "Bad number of arg for DefenderVar()\n");
	}
	return AliasUnitVar(l, "Defender");
}

ActiveUnitVar


Return equivalent lua table for .
{"Unit", {Unit = "Active", Variable = arg1, Component = "Value" or arg2}}

@param l Lua state.

@return equivalent lua table.

/stratagus/script.cpp:1530 CclActiveUnitVar

static int CclActiveUnitVar(lua_State *l)
{
	if (lua_gettop(l) == 0 || lua_gettop(l) > 3) {
		LuaError(l, "Bad number of arg for ActiveUnitVar()\n");
	}
	return AliasUnitVar(l, "Active");
}

TypeVar


Return equivalent lua table for .
{"Type", {Type = "Active", Variable = arg1, Component = "Value" or arg2}}

@param l Lua state.

@return equivalent lua table.

/stratagus/script.cpp:1546 CclActiveTypeVar

static int CclActiveTypeVar(lua_State *l)
{
	if (lua_gettop(l) == 0 || lua_gettop(l) > 3) {
		LuaError(l, "Bad number of arg for ActiveTypeVar()\n");
	}
	return AliasTypeVar(l, "Type");
}

Concat


Return equivalent lua table for Concat.
{"Concat", {arg1}}

@param l Lua state.

@return equivalent lua table.

/stratagus/script.cpp:1767 CclConcat

static int CclConcat(lua_State *l)
{
	if (lua_gettop(l) < 1) { // FIXME do extra job for 1.
		LuaError(l, "Bad number of arg for Concat()\n");
	}
	return Alias(l, "Concat");
}

String


Return equivalent lua table for String.
{"String", {arg1}}

@param l Lua state.

@return equivalent lua table.

/stratagus/script.cpp:1781 CclString

static int CclString(lua_State *l)
{
	LuaCheckArgs(l, 1);
	return Alias(l, "String");
}

InverseVideo


Return equivalent lua table for InverseVideo.
{"InverseVideo", {arg1}}

@param l Lua state.

@return equivalent lua table.

/stratagus/script.cpp:1794 CclInverseVideo

static int CclInverseVideo(lua_State *l)
{
	LuaCheckArgs(l, 1);
	return Alias(l, "InverseVideo");
}

UnitName


Return equivalent lua table for UnitName.
{"UnitName", {arg1}}

@param l Lua state.

@return equivalent lua table.

Example:

u_data = UnitType("unit-footman")

/stratagus/script.cpp:1811 CclUnitName

static int CclUnitName(lua_State *l)
{
	LuaCheckArgs(l, 1);
	return Alias(l, "UnitName");
}

SubString


Return equivalent lua table for SubString.
{"SubString", {arg1, arg2, arg3}}

@param l Lua state.

@return equivalent lua table.

/stratagus/script.cpp:1842 CclSubString

static int CclSubString(lua_State *l)
{
	if (lua_gettop(l) != 2 && lua_gettop(l) != 3) {
		LuaError(l, "Bad number of arg for SubString()\n");
	}
	return Alias(l, "SubString");
}

Line


Return equivalent lua table for Line.
{"Line", {arg1, arg2[, arg3]}}

@param l Lua state.

@return equivalent lua table.

/stratagus/script.cpp:1858 CclLine

static int CclLine(lua_State *l)
{
	if (lua_gettop(l) < 2 || lua_gettop(l) > 4) {
		LuaError(l, "Bad number of arg for Line()\n");
	}
	return Alias(l, "Line");
}

GameInfo


Return equivalent lua table for Line.
{"Line", "arg1"}

@param l Lua state.

@return equivalent lua table.

/stratagus/script.cpp:1872 CclGameInfo

static int CclGameInfo(lua_State *l)
{
	LuaCheckArgs(l, 1);
	return Alias(l, "GameInfo");
}

PlayerName


Return equivalent lua table for PlayerName.
{"PlayerName", {arg1}}

@param l Lua state.

@return equivalent lua table.

/stratagus/script.cpp:1961 CclPlayerName

static int CclPlayerName(lua_State *l)
{
	LuaCheckArgs(l, 1);
	return Alias(l, "PlayerName");
}

PlayerData


Return equivalent lua table for PlayerData.
{"PlayerData", {arg1}}

@param l Lua state.

@return equivalent lua table.

/stratagus/script.cpp:1947 CclPlayerData

static int CclPlayerData(lua_State *l)
{
	if (lua_gettop(l) != 2 && lua_gettop(l) != 3) {
		LuaError(l, "Bad number of arg for PlayerData()\n");
	}
	return Alias(l, "PlayerData");
}

If


Return equivalent lua table for If.
{"If", {arg1}}

@param l Lua state.

@return equivalent lua table.

/stratagus/script.cpp:1826 CclIf

static int CclIf(lua_State *l)
{
	if (lua_gettop(l) != 2 && lua_gettop(l) != 3) {
		LuaError(l, "Bad number of arg for If()\n");
	}
	return Alias(l, "If");
}

NumIf


Return equivalent lua table for NumIf.
{"NumIf", {arg1}}

@param l Lua state.

@return equivalent lua table.

/stratagus/script.cpp:1931 CclNumIf

static int CclNumIf(lua_State *l)
{
	if (lua_gettop(l) != 2 && lua_gettop(l) != 3) {
		LuaError(l, "Bad number of arg for NumIf()\n");
	}
	return Alias(l, "NumIf");
}

LibraryPath


Return the stratagus library path.

@param l Lua state.

@return Current libray path.

/stratagus/script.cpp:2023 CclStratagusLibraryPath

static int CclStratagusLibraryPath(lua_State *l)
{
	lua_pushstring(l, StratagusLibPath.c_str());
	return 1;
}

ListDirectory


Return a table with the files or directories found in the subdirectory.

/stratagus/script.cpp:2085 CclListDirectory

static int CclListDirectory(lua_State *l)
{
	return CclFilteredListDirectory(l, 0, 0);
}

ListFilesInDirectory


Return a table with the files found in the subdirectory.

/stratagus/script.cpp:2093 CclListFilesInDirectory

static int CclListFilesInDirectory(lua_State *l)
{
	return CclFilteredListDirectory(l, 0x1, 0x1);
}

ListDirsInDirectory


Return a table with the files found in the subdirectory.

/stratagus/script.cpp:2101 CclListDirsInDirectory

static int CclListDirsInDirectory(lua_State *l)
{
	return CclFilteredListDirectory(l, 0x0, 0x1);
}

ListFilesystem

/stratagus/script.cpp:2701 CclListFilesystem

static int CclListFilesystem(lua_State *l)
{
	LuaCheckArgs(l, 1);
	const char *dir = LuaToString(l, 1);

#ifdef WIN32
	if (strcmp(dir, "/") == 0) {
		std::vector<fs::path> vols = getVolumes();
		lua_newtable(l);	
		int j = 0;
		for (auto const& vol: vols) {
			if (!access(vol.generic_u8string().c_str(), R_OK)) {
				lua_pushnumber(l, ++j);
				lua_pushstring(l, vol.generic_u8string().c_str());
				lua_settable(l, -3);
			}
		}
		return 1;
	}
#endif

	lua_newtable(l);
	int j = 0;
	for (auto const& dir_entry: fs::directory_iterator(fs::path(dir))) {
		if ((fs::is_regular_file(dir_entry.path()) || fs::is_directory(dir_entry.path())) && !access(dir_entry.path().generic_u8string().c_str(), R_OK)) {
			std::string name = dir_entry.path().generic_u8string();
			if (fs::is_directory(dir_entry.path())) {
				name += "/";
			}
			lua_pushnumber(l, ++j);
			lua_pushstring(l, name.c_str());
			lua_settable(l, -3);
		}
	}

	return 1;
}

SetDamageFormula


Set damage computation method.

@param l Lua state.

/stratagus/script.cpp:2117 CclSetDamageFormula

static int CclSetDamageFormula(lua_State *l)
{
	Assert(l);
	if (Damage) {
		FreeNumberDesc(Damage);
		delete Damage;
	}
	Damage = CclParseNumberDesc(l);
	return 0;
}

SavePreferences


Save preferences

@param l Lua state.

/stratagus/script.cpp:293 CclSavePreferences

static int CclSavePreferences(lua_State *l)
{
	LuaCheckArgs(l, 0);
	SavePreferences();
	return 0;
}

Load


Load a file and execute it.

@param l Lua state.

@return 0 in success, else exit.

/stratagus/script.cpp:314 CclLoad

static int CclLoad(lua_State *l)
{
	const int arg = lua_gettop(l);
	if (arg < 1 || arg > 2) {
		LuaError(l, "incorrect argument");
	}
	const std::string filename = LibraryFileName(LuaToString(l, 1));
	bool exitOnError = arg == 2 ? LuaToBoolean(l, 2) : true;
	if (LuaLoadFile(filename, "", exitOnError) == -1) {
		DebugPrint("Load failed: %s\n" _C_ filename.c_str());
	}
	return 0;
}

LoadBuffer


Load a file into a buffer and return it.

@param l Lua state.

@return buffer or nil on failure

/stratagus/script.cpp:334 CclLoadBuffer

static int CclLoadBuffer(lua_State *l)
{
	LuaCheckArgs(l, 1);
	const std::string file = LibraryFileName(LuaToString(l, 1));
	DebugPrint("Loading '%s'\n" _C_ file.c_str());
	std::string content;
	if (GetFileContent(file, content) == false) {
		return 0;
	}
	lua_pushstring(l, content.c_str());
	return 1;
}

DebugPrint


Print debug message with info about current script name, line number and function.

@see DebugPrint

@param l Lua state.

/stratagus/script.cpp:2138 CclDebugPrint

static int CclDebugPrint(lua_State *l)
{
	LuaCheckArgs(l, 1);

#ifdef DEBUG
	lua_Debug ar;
	lua_getstack(l, 1, &ar);
	lua_getinfo(l, "nSl", &ar);
	fprintf(stdout, "%s:%d: %s: %s\n", ar.source, ar.currentline, ar.what, LuaToString(l, 1));
#endif

	return 1;
}

RestartStratagus


Restart the entire game. This function only returns when an error happens.

/stratagus/script.cpp:2179 CclRestartStratagus

static int CclRestartStratagus(lua_State *l)
{
	LuaCheckArgs(l, 0);
#ifdef WIN32
	char executable_path[MAX_PATH];
	memset(executable_path, 0, sizeof(executable_path));
	GetModuleFileName(NULL, executable_path, sizeof(executable_path)-1);
#else
	char *executable_path = const_cast<char*>(OriginalArgv[0].c_str());
#endif
	bool insertRestartArgument = true;
	for (auto arg : OriginalArgv) {
		if (arg == "-r") {
			insertRestartArgument = false;
			break;
		}
	}
	std::vector<std::string> quotedArgs = QuoteArguments(OriginalArgv);

	int newArgc = quotedArgs.size() + (insertRestartArgument ? 2 : 1);
	char **argv = new char*[newArgc];
	for (unsigned int i = 0; i < quotedArgs.size(); i++) {
		argv[i] = const_cast<char*>(quotedArgs[i].c_str());
	}
	if (insertRestartArgument) {
		argv[newArgc - 2] = (char*)"-r";
	}
	argv[newArgc - 1] = (char *)0;
#ifdef WIN32
	_execv(executable_path, argv);
#else
	execvp(executable_path, argv);
#endif
	delete[] argv;

	return 0;
}


/pathfinder/script_pathfinder.cpp
AStar


Enable a*.

@param l Lua state.

/pathfinder/script_pathfinder.cpp:110 CclAStar

static int CclAStar(lua_State *l)
{
	const char *value;
	int i;
	int j;
	int args;

	args = lua_gettop(l);
	for (j = 0; j < args; ++j) {
		value = LuaToString(l, j + 1);
		if (!strcmp(value, "fixed-unit-cost")) {
			++j;
			i = LuaToNumber(l, j + 1);
			if (i <= 3) {
				PrintFunction();
				fprintf(stdout, "Fixed unit crossing cost must be strictly > 3\n");
			} else {
				AStarFixedUnitCrossingCost = i;
			}
		} else if (!strcmp(value, "moving-unit-cost")) {
			++j;
			i = LuaToNumber(l, j + 1);
			if (i <= 3) {
				PrintFunction();
				fprintf(stdout, "Moving unit crossing cost must be strictly > 3\n");
			} else {
				AStarMovingUnitCrossingCost = i;
			}
		} else if (!strcmp(value, "know-unseen-terrain")) {
			AStarKnowUnseenTerrain = true;
		} else if (!strcmp(value, "dont-know-unseen-terrain")) {
			AStarKnowUnseenTerrain = false;
		} else if (!strcmp(value, "unseen-terrain-cost")) {
			++j;
			i = LuaToNumber(l, j + 1);
			if (i < 0) {
				PrintFunction();
				fprintf(stdout, "Unseen Terrain Cost must be non-negative\n");
			} else {
				AStarUnknownTerrainCost = i;
			}
		} else if (!strcmp(value, "max-search-iterations")) {
			++j;
			i = LuaToNumber(l, j + 1);
			if (i <= 0) {
				PrintFunction();
				fprintf(stdout, "Max A* search iterations must be strictly > 0\n");
			} else {
				AStarMaxSearchIterations = i;
			}
		} else {
			LuaError(l, "Unsupported tag: %s" _C_ value);
		}
	}

	return 0;
}


/game/game.cpp
SetGameName


Description

Return of game name.

@param l Lua state.

Example:

SetGameName("Wargus Map - Chapter 1")

/game/game.cpp:1152 CclSetGameName

static int CclSetGameName(lua_State *l)
{
	const int args = lua_gettop(l);
	if (args > 1 || (args == 1 && (!lua_isnil(l, 1) && !lua_isstring(l, 1)))) {
		LuaError(l, "incorrect argument");
	}
	if (args == 1 && !lua_isnil(l, 1)) {
		GameName = lua_tostring(l, 1);
	}

	if (!GameName.empty()) {
		std::string path = Parameters::Instance.GetUserDirectory() + "/" + GameName;
		makedir(path.c_str(), 0777);
	}
	return 0;
}

SetFullGameName

/game/game.cpp:1164 CclSetFullGameName

static int CclSetFullGameName(lua_State *l)
{
	const int args = lua_gettop(l);
	if (args > 1 || (args == 1 && (!lua_isnil(l, 1) && !lua_isstring(l, 1)))) {
		LuaError(l, "incorrect argument");
	}
	if (args == 1 && !lua_isnil(l, 1)) {
		FullGameName = lua_tostring(l, 1);
	}
	return 0;
}

SetGodMode


Description

Set God mode.

@param l Lua state.

@return The old mode.

Example:

-- God Mode enabled
SetGodMode(true)
-- God Mode disabled
SetGodMode(false)

/game/game.cpp:1187 CclSetGodMode

static int CclSetGodMode(lua_State *l)
{
	LuaCheckArgs(l, 1);
	GodMode = LuaToBoolean(l, 1);
	return 0;
}

GetGodMode


Description

Get God mode.

@param l Lua state.

@return God mode.

Example:

g_mode = GetGodMode()
print(g_mode)

/game/game.cpp:1208 CclGetGodMode

static int CclGetGodMode(lua_State *l)
{
	LuaCheckArgs(l, 0);
	lua_pushboolean(l, GodMode);
	return 1;
}

SetSpeedResourcesHarvest


Set resource harvesting speed (deprecated).

@param l Lua state.

/game/game.cpp:1225 CclSetSpeedResourcesHarvest

static int CclSetSpeedResourcesHarvest(lua_State *l)
{
	LuaCheckArgs(l, 3);

	const int player = LuaToNumber(l, 1);
	const std::string resource = LuaToString(l, 2);
	const int resId = GetResourceIdByName(l, resource.c_str());

	Players[player].SpeedResourcesHarvest[resId] = LuaToNumber(l, 3);
	return 0;
}

SetSpeedResourcesReturn


Set resource returning speed (deprecated).

@param l Lua state.

/game/game.cpp:1242 CclSetSpeedResourcesReturn

static int CclSetSpeedResourcesReturn(lua_State *l)
{
	LuaCheckArgs(l, 3);

	const int player = LuaToNumber(l, 1);
	const std::string resource = LuaToString(l, 2);
	const int resId = GetResourceIdByName(l, resource.c_str());

	Players[player].SpeedResourcesReturn[resId] = LuaToNumber(l, 3);
	return 0;
}

SetSpeedBuild


Set building speed (deprecated).

@param l Lua state.

/game/game.cpp:1255 CclSetSpeedBuild

static int CclSetSpeedBuild(lua_State *l)
{
	LuaCheckArgs(l, 2);
	const int player = LuaToNumber(l, 1);
	Players[player].SpeedBuild = LuaToNumber(l, 2);
	return 0;
}

GetSpeedBuild


Get building speed (deprecated).

@param l Lua state.

@return Building speed.

/game/game.cpp:1270 CclGetSpeedBuild

static int CclGetSpeedBuild(lua_State *l)
{
	LuaCheckArgs(l, 1);
	const int player = LuaToNumber(l, 1);
	lua_pushnumber(l, Players[player].SpeedBuild);
	return 1;
}

SetSpeedTrain


Set training speed (deprecated).

@param l Lua state.

/game/game.cpp:1283 CclSetSpeedTrain

static int CclSetSpeedTrain(lua_State *l)
{
	LuaCheckArgs(l, 2);
	const int player = LuaToNumber(l, 1);
	Players[player].SpeedTrain = LuaToNumber(l, 2);
	return 0;
}

GetSpeedTrain


Get training speed (deprecated).

@param l Lua state.

@return Training speed.

/game/game.cpp:1298 CclGetSpeedTrain

static int CclGetSpeedTrain(lua_State *l)
{
	LuaCheckArgs(l, 1);
	const int player = LuaToNumber(l, 1);
	lua_pushnumber(l, Players[player].SpeedTrain);
	return 1;
}

SetSpeedUpgrade


For debug increase upgrading speed (deprecated).

@param l Lua state.

/game/game.cpp:1313 CclSetSpeedUpgrade

static int CclSetSpeedUpgrade(lua_State *l)
{
	LuaCheckArgs(l, 2);
	const int player = LuaToNumber(l, 1);
	Players[player].SpeedUpgrade = LuaToNumber(l, 2);

	lua_pushnumber(l, Players[player].SpeedUpgrade);
	return 1;
}

SetSpeedResearch


For debug increase researching speed (deprecated).

@param l Lua state.

/game/game.cpp:1328 CclSetSpeedResearch

static int CclSetSpeedResearch(lua_State *l)
{
	LuaCheckArgs(l, 2);
	const int player = LuaToNumber(l, 1);
	Players[player].SpeedResearch = LuaToNumber(l, 2);

	lua_pushnumber(l, Players[player].SpeedResearch);
	return 1;
}

SetSpeeds


For debug increase all speeds (deprecated).

@param l Lua state.

/game/game.cpp:1349 CclSetSpeeds

static int CclSetSpeeds(lua_State *l)
{
	LuaCheckArgs(l, 1);
	const int speed = LuaToNumber(l, 1);
	for (int i = 0; i < PlayerMax; ++i) {
		for (int j = 0; j < MaxCosts; ++j) {
			Players[i].SpeedResourcesHarvest[j] = speed;
			Players[i].SpeedResourcesReturn[j] = speed;
		}
		Players[i].SpeedBuild = Players[i].SpeedTrain = Players[i].SpeedUpgrade = Players[i].SpeedResearch = speed;
	}

	lua_pushnumber(l, speed);
	return 1;
}

DefineDefaultIncomes


Define default incomes for a new player.

@param l Lua state.

/game/game.cpp:1363 CclDefineDefaultIncomes

static int CclDefineDefaultIncomes(lua_State *l)
{
	const int args = lua_gettop(l);
	for (int i = 0; i < MaxCosts && i < args; ++i) {
		DefaultIncomes[i] = LuaToNumber(l, i + 1);
	}
	return 0;
}

DefineDefaultActions


Define default action for the resources.

@param l Lua state.

/game/game.cpp:1380 CclDefineDefaultActions

static int CclDefineDefaultActions(lua_State *l)
{
	for (unsigned int i = 0; i < MaxCosts; ++i) {
		DefaultActions[i].clear();
	}
	const unsigned int args = lua_gettop(l);
	for (unsigned int i = 0; i < MaxCosts && i < args; ++i) {
		DefaultActions[i] = LuaToString(l, i + 1);
	}
	return 0;
}

DefineDefaultResourceNames


Define default names for the resources.

@param l Lua state.

/game/game.cpp:1397 CclDefineDefaultResourceNames

static int CclDefineDefaultResourceNames(lua_State *l)
{
	for (unsigned int i = 0; i < MaxCosts; ++i) {
		DefaultResourceNames[i].clear();
	}
	const unsigned int args = lua_gettop(l);
	for (unsigned int i = 0; i < MaxCosts && i < args; ++i) {
		DefaultResourceNames[i] = LuaToString(l, i + 1);
	}
	return 0;
}

DefineDefaultResourceAmounts


Define default names for the resources.

@param l Lua state.

/game/game.cpp:1419 CclDefineDefaultResourceAmounts

static int CclDefineDefaultResourceAmounts(lua_State *l)
{
	const unsigned int args = lua_gettop(l);

	if (args & 1) {
		LuaError(l, "incorrect argument");
	}
	for (unsigned int j = 0; j < args; ++j) {
		const std::string resource = LuaToString(l, j + 1);
		const int resId = GetResourceIdByName(l, resource.c_str());

		++j;
		DefaultResourceAmounts[resId] = LuaToNumber(l, j + 1);
	}
	return 0;
}

DefineDefaultResourceMaxAmounts


Define max amounts for the resources.

@param l Lua state.

/game/game.cpp:1437 CclDefineDefaultResourceMaxAmounts

static int CclDefineDefaultResourceMaxAmounts(lua_State *l)
{
	const int args = std::min<int>(lua_gettop(l), MaxCosts);

	for (int i = 0; i < args; ++i) {
		DefaultResourceMaxAmounts[i] = LuaToNumber(l, i + 1);
	}
	for (int i = args; i < MaxCosts; ++i) {
		DefaultResourceMaxAmounts[i] = -1;
	}
	return 0;
}

SetUseHPForXp


Affect UseHPForXp.

@param l Lua state.

@return 0.

/game/game.cpp:1451 ScriptSetUseHPForXp

static int ScriptSetUseHPForXp(lua_State *l)
{
	LuaCheckArgs(l, 1);
	UseHPForXp = LuaToBoolean(l, 1);
	return 0;
}

SetLocalPlayerName


Description

Set the local player name

@param l Lua state.

Example:

SetLocalPlayerName("Stormreaver Clan")

/game/game.cpp:1469 CclSetLocalPlayerName

static int CclSetLocalPlayerName(lua_State *l)
{
	LuaCheckArgs(l, 1);
	Parameters::Instance.LocalPlayerName = LuaToString(l, 1);
	return 0;
}

GetLocalPlayerName


Description

Get the local player name

@param l Lua state.

Example:

GetLocalPlayerName()

/game/game.cpp:1487 CclGetLocalPlayerName

static int CclGetLocalPlayerName(lua_State *l)
{
	LuaCheckArgs(l, 0);
	lua_pushstring(l, Parameters::Instance.LocalPlayerName.c_str());
	return 1;
}

SetMenuRace

/game/game.cpp:1528 CclSetMenuRace

static int CclSetMenuRace(lua_State *l)
{
	LuaCheckArgs(l, 1);
	MenuRace = LuaToString(l, 1);
	return 0;
}

GetStratagusVersion


Description

Get Stratagus Version

Example:

version = GetStratagusVersion()
print(version)

/game/game.cpp:1504 CclGetStratagusVersion

static int CclGetStratagusVersion(lua_State *l)
{
	LuaCheckArgs(l, 0);
	lua_pushstring(l, VERSION);
	return 1;
}

GetStratagusHomepage


Description

Get Stratagus Homepage

Example:

url = GetStratagusHomepage()
print(url)

/game/game.cpp:1521 CclGetStratagusHomepage

static int CclGetStratagusHomepage(lua_State *l)
{
	LuaCheckArgs(l, 0);
	lua_pushstring(l, HOMEPAGE);
	return 1;
}

SavedGameInfo


Load the SavedGameInfo Header

@param l Lua state.

/game/game.cpp:1564 CclSavedGameInfo

static int CclSavedGameInfo(lua_State *l)
{
	LuaCheckArgs(l, 1);
	if (!lua_istable(l, 1)) {
		LuaError(l, "incorrect argument");
	}

	for (lua_pushnil(l); lua_next(l, 1); lua_pop(l, 1)) {
		const char *value = LuaToString(l, -2);

		if (!strcmp(value, "SaveFile")) {
			if (strcpy_s(CurrentMapPath, sizeof(CurrentMapPath), LuaToString(l, -1)) != 0) {
				LuaError(l, "SaveFile too long");
			}
			std::string buf = StratagusLibPath;
			buf += "/";
			buf += LuaToString(l, -1);
			if (LuaLoadFile(buf) == -1) {
				DebugPrint("Load failed: %s\n" _C_ value);
			}
		} else if (!strcmp(value, "SyncHash")) {
			SyncHash = LuaToNumber(l, -1);
		} else if (!strcmp(value, "SyncRandSeed")) {
			SyncRandSeed = LuaToNumber(l, -1);
		} else {
			LuaError(l, "Unsupported tag: %s" _C_ value);
		}
	}
	return 0;
}


/game/trigger.cpp
AddTrigger


Description

Add a trigger.

Example:

AddTrigger(
function() return (GetPlayerData(1,"UnitTypesCount","unit-farm") >= 4) end,
function() return ActionVictory() end
)

/game/trigger.cpp:507 CclAddTrigger

static int CclAddTrigger(lua_State *l)
{
	LuaCheckArgs(l, 2);
	if (!lua_isfunction(l, 1)
		|| (!lua_isfunction(l, 2) && !lua_istable(l, 2))) {
		LuaError(l, "incorrect argument");
	}

	// Make a list of all triggers.
	// A trigger is a pair of condition and action
	lua_getglobal(l, "_triggers_");

	if (lua_isnil(l, -1)) {
		DebugPrint("Trigger not set, defining trigger\n");
		lua_pop(l, 1);
		lua_newtable(l);
		lua_setglobal(l, "_triggers_");
		lua_getglobal(l, "_triggers_");
	}

	const int i = lua_rawlen(l, -1);
	if (ActiveTriggers && !ActiveTriggers[i / 2]) {
		lua_pushnil(l);
		lua_rawseti(l, -2, i + 1);
		lua_pushnil(l);
		lua_rawseti(l, -2, i + 2);
	} else {
		lua_pushvalue(l, 1);
		lua_rawseti(l, -2, i + 1);
		lua_newtable(l);
		lua_pushvalue(l, 2);
		lua_rawseti(l, -2, 1);
		lua_rawseti(l, -2, i + 2);
	}
	lua_pop(l, 1);

	return 0;
}

SetActiveTriggers


Set the active triggers

/game/trigger.cpp:529 CclSetActiveTriggers

static int CclSetActiveTriggers(lua_State *l)
{
	const int args = lua_gettop(l);

	ActiveTriggers = new bool[args];
	for (int j = 0; j < args; ++j) {
		ActiveTriggers[j] = LuaToBoolean(l, j + 1);
	}
	return 0;
}

GetNumUnitsAt


Description

Return the number of units of a given unit-type and player at a location.

Example:

-- Get the number of knights from player 1 from position 0,0 to 20,15
num_units = GetNumUnitsAt(1,"unit-knight",{0,0},{20,15})
print(num_units)

/game/trigger.cpp:211 CclGetNumUnitsAt

static int CclGetNumUnitsAt(lua_State *l)
{
	LuaCheckArgs(l, 4);

	int plynr = LuaToNumber(l, 1);
	lua_pushvalue(l, 2);
	const CUnitType *unittype = TriggerGetUnitType(l);
	lua_pop(l, 1);

	Vec2i minPos;
	Vec2i maxPos;
	CclGetPos(l, &minPos.x, &minPos.y, 3);
	CclGetPos(l, &maxPos.x, &maxPos.y, 4);

	if (minPos.x > maxPos.x) {
		std::swap(minPos.x, maxPos.x);
	}
	if (minPos.y > maxPos.y) {
		std::swap(minPos.y, maxPos.y);
	}

	std::vector<CUnit *> units;

	Select(minPos, maxPos, units);

	int s = 0;
	for (size_t i = 0; i != units.size(); ++i) {
		const CUnit &unit = *units[i];
		// Check unit type

		if (unittype == ANY_UNIT
			|| (unittype == ALL_FOODUNITS && !unit.Type->Building)
			|| (unittype == ALL_BUILDINGS && unit.Type->Building)
			|| (unittype == unit.Type && !unit.Constructed)) {

			// Check the player
			if (plynr == -1 || plynr == unit.Player->Index) {
				if (unit.IsAlive()) {
					++s;
				}
			}
		}
	}
	lua_pushnumber(l, s);
	return 1;
}

IfNearUnit


Description

Player has the quantity of unit-type near to unit-type.

Example:

AddTrigger(
function() return IfNearUnit(0,">",1,"unit-peasant","unit-town-hall") end,
function()
AddMessage("Player 0 has more than 1 peasant near the Town Hall")
return false end
)

/game/trigger.cpp:284 CclIfNearUnit

static int CclIfNearUnit(lua_State *l)
{
	LuaCheckArgs(l, 5);
	lua_pushvalue(l, 1);
	const int plynr = TriggerGetPlayer(l);
	lua_pop(l, 1);
	const char *op = LuaToString(l, 2);
	const int q = LuaToNumber(l, 3);
	lua_pushvalue(l, 4);
	const CUnitType *unittype = TriggerGetUnitType(l);
	lua_pop(l, 1);
	const CUnitType *ut2 = CclGetUnitType(l);
	if (!unittype || !ut2) {
		LuaError(l, "CclIfNearUnit: not a unit-type valid");
	}
	CompareFunction compare = GetCompareFunction(op);
	if (!compare) {
		LuaError(l, "Illegal comparison operation in if-near-unit: %s" _C_ op);
	}

	//
	// Get all unit types 'near'.
	//

	std::vector<CUnit *> unitsOfType;

	FindUnitsByType(*ut2, unitsOfType);
	for (size_t i = 0; i != unitsOfType.size(); ++i) {
		const CUnit &centerUnit = *unitsOfType[i];

		std::vector<CUnit *> around;
		SelectAroundUnit(centerUnit, 1, around);

		// Count the requested units
		int s = 0;
		for (size_t j = 0; j < around.size(); ++j) {
			const CUnit &unit = *around[j];

			// Check unit type
			if (unittype == ANY_UNIT
				|| (unittype == ALL_FOODUNITS && !unit.Type->Building)
				|| (unittype == ALL_BUILDINGS && unit.Type->Building)
				|| (unittype == unit.Type)) {

				// Check the player
				if (plynr == -1 || plynr == unit.Player->Index) {
					++s;
				}
			}
		}
		if (compare(s, q)) {
			lua_pushboolean(l, 1);
			return 1;
		}
	}
	lua_pushboolean(l, 0);
	return 1;
}

IfRescuedNearUnit


Description

Player has the quantity of rescued unit-type near to unit-type.

Example:

IfRescuedNearUnit("this", ">=", 1, "unit-archer", "unit-circle-of-power")

/game/trigger.cpp:352 CclIfRescuedNearUnit

static int CclIfRescuedNearUnit(lua_State *l)
{
	LuaCheckArgs(l, 5);

	lua_pushvalue(l, 1);
	const int plynr = TriggerGetPlayer(l);
	lua_pop(l, 1);
	const char *op = LuaToString(l, 2);
	const int q = LuaToNumber(l, 3);
	lua_pushvalue(l, 4);
	const CUnitType *unittype = TriggerGetUnitType(l);
	lua_pop(l, 1);
	const CUnitType *ut2 = CclGetUnitType(l);
	if (!unittype || !ut2) {
		LuaError(l, "CclIfRescuedNearUnit: not a unit-type valid");
	}

	CompareFunction compare = GetCompareFunction(op);
	if (!compare) {
		LuaError(l, "Illegal comparison operation in if-rescued-near-unit: %s" _C_ op);
	}

	// Get all unit types 'near'.
	std::vector<CUnit *> table;
	FindUnitsByType(*ut2, table);
	for (size_t i = 0; i != table.size(); ++i) {
		CUnit &centerUnit = *table[i];
		std::vector<CUnit *> around;

		SelectAroundUnit(centerUnit, 1, around);
		// Count the requested units
		int s = 0;
		for (size_t j = 0; j != around.size(); ++j) {
			CUnit &unit = *around[j];

			if (unit.RescuedFrom) { // only rescued units
				// Check unit type

				if (unittype == ANY_UNIT
					|| (unittype == ALL_FOODUNITS && !unit.Type->Building)
					|| (unittype == ALL_BUILDINGS && unit.Type->Building)
					|| (unittype == unit.Type)) {

					// Check the player
					if (plynr == -1 || plynr == unit.Player->Index) {
						++s;
					}
				}
			}
		}
		if (compare(s, q)) {
			lua_pushboolean(l, 1);
			return 1;
		}
	}
	lua_pushboolean(l, 0);
	return 1;
}


/game/replay.cpp
Log


Parse log

/game/replay.cpp:519 CclLog

static int CclLog(lua_State *l)
{
	LogEntry *log;
	LogEntry **last;
	const char *value;

	LuaCheckArgs(l, 1);
	if (!lua_istable(l, 1)) {
		LuaError(l, "incorrect argument");
	}

	Assert(CurrentReplay);

	log = new LogEntry;
	log->UnitNumber = -1;
	log->PosX = -1;
	log->PosY = -1;
	log->DestUnitNumber = -1;
	log->Num = -1;

	lua_pushnil(l);
	while (lua_next(l, 1)) {
		value = LuaToString(l, -2);
		if (!strcmp(value, "GameCycle")) {
			log->GameCycle = LuaToNumber(l, -1);
		} else if (!strcmp(value, "UnitNumber")) {
			log->UnitNumber = LuaToNumber(l, -1);
		} else if (!strcmp(value, "UnitIdent")) {
			log->UnitIdent = LuaToString(l, -1);
		} else if (!strcmp(value, "Action")) {
			log->Action = LuaToString(l, -1);
		} else if (!strcmp(value, "Flush")) {
			log->Flush = LuaToNumber(l, -1);
		} else if (!strcmp(value, "PosX")) {
			log->PosX = LuaToNumber(l, -1);
		} else if (!strcmp(value, "PosY")) {
			log->PosY = LuaToNumber(l, -1);
		} else if (!strcmp(value, "DestUnitNumber")) {
			log->DestUnitNumber = LuaToNumber(l, -1);
		} else if (!strcmp(value, "Value")) {
			log->Value = LuaToString(l, -1);
		} else if (!strcmp(value, "Num")) {
			log->Num = LuaToNumber(l, -1);
		} else if (!strcmp(value, "SyncRandSeed")) {
			log->SyncRandSeed = lua_tointeger(l, -1);
		} else {
			LuaError(l, "Unsupported key: %s" _C_ value);
		}
		lua_pop(l, 1);
	}

	// Append to linked list
	last = &CurrentReplay->Commands;
	while (*last) {
		last = &(*last)->Next;
	}

	*last = log;

	return 0;
}

ReplayLog


Parse replay-log

/game/replay.cpp:624 CclReplayLog

static int CclReplayLog(lua_State *l)
{
	FullReplay *replay;
	const char *value;
	int j;

	LuaCheckArgs(l, 1);
	if (!lua_istable(l, 1)) {
		LuaError(l, "incorrect argument");
	}

	Assert(CurrentReplay == NULL);

	replay = new FullReplay;

	lua_pushnil(l);
	while (lua_next(l, 1) != 0) {
		value = LuaToString(l, -2);
		if (!strcmp(value, "Comment1")) {
			replay->Comment1 = LuaToString(l, -1);
		} else if (!strcmp(value, "Comment2")) {
			replay->Comment2 = LuaToString(l, -1);
		} else if (!strcmp(value, "Comment3")) {
			replay->Comment3 = LuaToString(l, -1);
		} else if (!strcmp(value, "Date")) {
			replay->Date = LuaToString(l, -1);
		} else if (!strcmp(value, "Map")) {
			replay->Map = LuaToString(l, -1);
		} else if (!strcmp(value, "MapPath")) {
			replay->MapPath = LuaToString(l, -1);
		} else if (!strcmp(value, "MapId")) {
			replay->MapId = LuaToNumber(l, -1);
		} else if (!strcmp(value, "LocalPlayer")) {
			replay->LocalPlayer = LuaToNumber(l, -1);
		} else if (!strcmp(value, "Players")) {
			if (!lua_istable(l, -1) || lua_rawlen(l, -1) != PlayerMax) {
				LuaError(l, "incorrect argument");
			}
			for (j = 0; j < PlayerMax; ++j) {
				int top;

				lua_rawgeti(l, -1, j + 1);
				if (!lua_istable(l, -1)) {
					LuaError(l, "incorrect argument");
				}
				top = lua_gettop(l);
				lua_pushnil(l);
				while (lua_next(l, top) != 0) {
					value = LuaToString(l, -2);
					if (!strcmp(value, "Name")) {
						replay->PlayerNames[j] = LuaToString(l, -1);
					} else if (!strcmp(value, "AIScript")) {
						replay->ReplaySettings.Presets[j].AIScript = LuaToString(l, -1);
					} else if (!strcmp(value, "PlayerColor")) {
						replay->ReplaySettings.Presets[j].PlayerColor = LuaToNumber(l, -1);
					} else if (!strcmp(value, "Race")) {
						replay->ReplaySettings.Presets[j].Race = LuaToNumber(l, -1);
					} else if (!strcmp(value, "Team")) {
						replay->ReplaySettings.Presets[j].Team = LuaToNumber(l, -1);
					} else if (!strcmp(value, "Type")) {
						replay->ReplaySettings.Presets[j].Type = static_cast<PlayerTypes>(LuaToNumber(l, -1));
					} else {
						LuaError(l, "Unsupported key: %s" _C_ value);
					}
					lua_pop(l, 1);
				}
				lua_pop(l, 1);
			}
		} else if (!strcmp(value, "Engine")) {
			if (!lua_istable(l, -1) || lua_rawlen(l, -1) != 3) {
				LuaError(l, "incorrect argument");
			}
			replay->Engine[0] = LuaToNumber(l, -1, 1);
			replay->Engine[1] = LuaToNumber(l, -1, 2);
			replay->Engine[2] = LuaToNumber(l, -1, 3);
		} else if (!strcmp(value, "Network")) {
			if (!lua_istable(l, -1) || lua_rawlen(l, -1) != 3) {
				LuaError(l, "incorrect argument");
			}
			replay->Network[0] = LuaToNumber(l, -1, 1);
			replay->Network[1] = LuaToNumber(l, -1, 2);
			replay->Network[2] = LuaToNumber(l, -1, 3);
		} else {
			if (!replay->ReplaySettings.SetField(value, LuaToNumber(l, -1))) {
				LuaError(l, "Unsupported key: %s" _C_ value);
			}
		}
		lua_pop(l, 1);
	}

	CurrentReplay = replay;

	// Apply CurrentReplay settings.
	if (!SaveGameLoading) {
		ApplyReplaySettings();
	} else {
		CommandLogDisabled = false;
	}

	return 0;
}


/ai/script_ai.cpp
DefineAiHelper


Define helper for AI.

@param l Lua state.

@todo FIXME: the first unit could be a list see ../doc/ccl/ai.html

/ai/script_ai.cpp:356 CclDefineAiHelper

static int CclDefineAiHelper(lua_State *l)
{
	InitAiHelper(AiHelpers);

	const int args = lua_gettop(l);
	for (int j = 0; j < args; ++j) {
		if (!lua_istable(l, j + 1)) {
			LuaError(l, "incorrect argument");
		}
		const int subargs = lua_rawlen(l, j + 1);
		const char *value = LuaToString(l, j + 1, 1);
		if (!strcmp(value, "build")
			|| !strcmp(value, "train")
			|| !strcmp(value, "upgrade")
			|| !strcmp(value, "research")
			|| !strcmp(value, "unit-limit")
			|| !strcmp(value, "repair")) {
#ifdef DEBUG
			fprintf(stderr, "DefineAiHelper: Relation is computed from buttons, you may remove safely the block beginning with '\"%s\"'\n", value);
#endif
			continue;
		} else if (!strcmp(value, "unit-equiv")) {
		} else {
			LuaError(l, "unknown tag: %s" _C_ value);
		}
		// Get the base unit type, which could handle the action.
		const char *baseTypeName = LuaToString(l, j + 1, 2);
		const CUnitType *base = UnitTypeByIdent(baseTypeName);
		if (!base) {
			LuaError(l, "unknown unittype: %s" _C_ baseTypeName);
		}

		// Get the unit types, which could be produced
		for (int k = 2; k < subargs; ++k) {
			const char *equivTypeName = LuaToString(l, j + 1, k + 1);
			CUnitType *type = UnitTypeByIdent(equivTypeName);
			if (!type) {
				LuaError(l, "unknown unittype: %s" _C_ equivTypeName);
			}
			AiHelperInsert(AiHelpers.Equiv(), base->Slot, *type);
			AiNewUnitTypeEquiv(*base, *type);
		}
	}
	return 0;
}

DefineAi


Description

Define an AI engine.

@param l Lua state.

@return FIXME: docu

Example:

-- Those instructions will be executed forever
local simple_ai_loop = {
-- Sleep for 5 in game minutes
function() return AiSleep(9000) end,
-- Repeat the functions from start.
function() stratagus.gameData.AIState.loop_index[1 + AiPlayer()] = 0; return false; end,
}

-- The initial instructions the A.I has to execute
local simple_ai = {
function() return AiSleep(1800) end, -- Sleep for 1 in game minute
function() return AiNeed("unit-town-hall") end, -- One Town Hall is needed
function() return AiWait("unit-town-hall") end, -- Wait until the Town Hall is completed
function() return AiSet("unit-peasant", 4) end, -- Make 4 peasants
-- Basic buildings
function() return AiSet("unit-farm", 4) end, -- Make 4 farms
function() return AiWait("unit-farm") end, -- Wait until all 4 farms are build.
function() return AiNeed("unit-human-barracks") end, -- Need a Barracks
function() return AiWait("unit-human-barracks") end, -- Wait until the Barracks has been built
-- Defense force for the base
function() return AiForce(1, {"unit-footman", 3}) end, -- Make a force of 3 footmen
function() return AiWaitForce(1) end, -- Wait until the 3 footmen are trained
function() return AiForceRole(1,"defend") end, -- Make this force as a defense force
-- Execute the instructions in simple_ai_loop
function() return AiLoop(simple_ai_loop, stratagus.gameData.AIState.loop_index) end,
}

-- function that calls the instructions in simple_ai inside DefineAi
function custom_ai() return AiLoop(simple_ai,stratagus.gameData.AIState.index) end
-- Make an A.I for the human race that calls the function custom_ai
DefineAi("example_ai","human","class_ai",custom_ai)

/ai/script_ai.cpp:458 CclDefineAi

static int CclDefineAi(lua_State *l)
{
	LuaCheckArgs(l, 4);
	if (!lua_isfunction(l, 4)) {
		LuaError(l, "incorrect argument");
	}

	CAiType *aitype = new CAiType;

	// AI Name
	const char *aiName = LuaToString(l, 1);
	aitype->Name = aiName;

#ifdef DEBUG
	if (GetAiTypesByName(aiName)) {
		DebugPrint("Warning two or more AI's with the same name '%s'\n" _C_ aiName);
	}
#endif
	AiTypes.insert(AiTypes.begin(), aitype);

	// AI Race
	const char *value = LuaToString(l, 2);
	if (*value != '*') {
		aitype->Race = value;
	} else {
		aitype->Race.clear();
	}

	// AI Class
	aitype->Class = LuaToString(l, 3);

	// AI Script
	lua_getglobal(l, "_ai_scripts_");
	if (lua_isnil(l, -1)) {
		lua_pop(l, 1);
		lua_newtable(l);
		lua_setglobal(l, "_ai_scripts_");
		lua_getglobal(l, "_ai_scripts_");
	}
	aitype->Script = aitype->Name + aitype->Race + aitype->Class;
	lua_pushstring(l, aitype->Script.c_str());
	lua_pushvalue(l, 4);
	lua_rawset(l, 5);
	lua_pop(l, 1);

	return 0;
}

AiGetRace


Get the race of the current AI player.

@param l Lua state.

/ai/script_ai.cpp:545 CclAiGetRace

static int CclAiGetRace(lua_State *l)
{
	LuaCheckArgs(l, 0);
	lua_pushstring(l, PlayerRaces.Name[AiPlayer->Player->Race].c_str());
	return 1;
}

AiGetSleepCycles


Description

Get the number of cycles to sleep.

@param l Lua state

@return Number of return values

Example:

local simple_ai_loop = {
-- Sleep for 5 in game minutes
function() return AiSleep(9000) end,
-- Repeat the instructions forever.
function() stratagus.gameData.AIState.loop_index[1 + AiPlayer()] = 0; return false; end,
}

local simple_ai = {
-- Get the number of cycles to sleep.
function() return AiSleep(AiGetSleepCycles()) end,
-- Execute the instructions in simple_ai_loop
function() return AiLoop(simple_ai_loop, stratagus.gameData.AIState.loop_index) end,
}

function custom_ai() return AiLoop(simple_ai,stratagus.gameData.AIState.index) end
DefineAi("example_ai","human","class_ai",custom_ai)

/ai/script_ai.cpp:580 CclAiGetSleepCycles

static int CclAiGetSleepCycles(lua_State *l)
{
	LuaCheckArgs(l, 0);
	lua_pushnumber(l, AiSleepCycles);
	return 1;
}

AiDebug


Set debugging flag of AI script

@param l Lua state

@return Number of return values

/ai/script_ai.cpp:596 CclAiDebug

static int CclAiDebug(lua_State *l)
{
	LuaCheckArgs(l, 1);
	AiPlayer->ScriptDebug = LuaToBoolean(l, 1);
	return 0;
}

AiDebugPlayer


Activate AI debugging for the given player(s)
Player can be a number for a specific player
"self" for current human player (ai me)
"none" to disable

@param l Lua State

@return Number of return values

/ai/script_ai.cpp:644 CclAiDebugPlayer

static int CclAiDebugPlayer(lua_State *l)
{
	const int args = lua_gettop(l);
	for (int j = 0; j < args; ++j) {
		const char *item;

		if (lua_isstring(l, j + 1)) {
			item = LuaToString(l, j + 1);
		} else {
			item = NULL;
		}
		if (item && !strcmp(item, "none")) {
			for (int i = 0; i != NumPlayers; ++i) {
				if (!Players[i].AiEnabled || !Players[i].Ai) {
					continue;
				}
				Players[i].Ai->ScriptDebug = 0;
			}
		} else {
			int playerid;
			if (item && !strcmp(item, "self")) {
				if (!ThisPlayer) {
					continue;
				}
				playerid = ThisPlayer->Index;
			} else {
				playerid = LuaToNumber(l, j + 1);
			}

			if (!Players[playerid].AiEnabled || !Players[playerid].Ai) {
				continue;
			}
			Players[playerid].Ai->ScriptDebug = 1;
		}
	}
	return 0;
}

AiNeed


Description

Need a unit.

@param l Lua state.

@return Number of return values

Example:

local simple_ai_loop = {
-- Sleep for 5 in game minutes
function() return AiSleep(9000) end,
-- Repeat the instructions forever.
function() stratagus.gameData.AIState.loop_index[1 + AiPlayer()] = 0; return false; end,
}

local simple_ai = {
function() return AiSleep(AiGetSleepCycles()) end,
-- Tell to the A.I that it needs a Town Hall.
function() return AiNeed("unit-town-hall") end,
-- Execute the instructions in simple_ai_loop
function() return AiLoop(simple_ai_loop, stratagus.gameData.AIState.loop_index) end,
}

function custom_ai() return AiLoop(simple_ai,stratagus.gameData.AIState.index) end
DefineAi("example_ai","human","class_ai",custom_ai)

/ai/script_ai.cpp:682 CclAiNeed

static int CclAiNeed(lua_State *l)
{
	LuaCheckArgs(l, 1);
	InsertUnitTypeRequests(CclGetUnitType(l), 1);

	lua_pushboolean(l, 0);
	return 1;
}

AiSet


Description

Set the number of units.

@param l Lua state

@return Number of return values

Example:

local simple_ai_loop = {
-- Sleep for 5 in game minutes
function() return AiSleep(9000) end,
-- Repeat the instructions forever.
function() stratagus.gameData.AIState.loop_index[1 + AiPlayer()] = 0; return false; end,
}

local simple_ai = {
function() return AiSleep(AiGetSleepCycles()) end,
-- Tell to the A.I that it needs a Town Hall.
function() return AiNeed("unit-town-hall") end,
-- Wait until the town-hall has been built.
function() return AiWait("unit-town-hall") end,
-- Tell to the A.I that it needs 4 peasants
function() return AiSet("unit-peasant",4) end,
-- Execute the instructions in simple_ai_loop
function() return AiLoop(simple_ai_loop, stratagus.gameData.AIState.loop_index) end,
}

function custom_ai() return AiLoop(simple_ai,stratagus.gameData.AIState.index) end
DefineAi("example_ai","human","class_ai",custom_ai)

/ai/script_ai.cpp:733 CclAiSet

static int CclAiSet(lua_State *l)
{
	LuaCheckArgs(l, 2);
	lua_pushvalue(l, 1);
	CUnitType *type = CclGetUnitType(l);
	lua_pop(l, 1);

	AiRequestType *autt = FindInUnitTypeRequests(type);
	if (autt) {
		autt->Count = LuaToNumber(l, 2);
		// FIXME: 0 should remove it.
	} else {
		InsertUnitTypeRequests(type, LuaToNumber(l, 2));
	}
	lua_pushboolean(l, 0);
	return 1;
}

AiWait


Description

Wait for a unit.

@param l Lua State.

@return Number of return values

Example:

local simple_ai_loop = {
-- Sleep for 5 in game minutes
function() return AiSleep(9000) end,
-- Repeat the instructions forever.
function() stratagus.gameData.AIState.loop_index[1 + AiPlayer()] = 0; return false; end,
}

local simple_ai = {
function() return AiSleep(AiGetSleepCycles()) end,
-- Tell to the A.I that it needs a Town Hall.
function() return AiNeed("unit-town-hall") end,
-- Wait until the Town Hall has been built.
function() return AiWait("unit-town-hall") end,
-- Execute the instructions in simple_ai_loop
function() return AiLoop(simple_ai_loop, stratagus.gameData.AIState.loop_index) end,
}

function custom_ai() return AiLoop(simple_ai,stratagus.gameData.AIState.index) end
DefineAi("example_ai","human","class_ai",custom_ai)

/ai/script_ai.cpp:813 CclAiWait

static int CclAiWait(lua_State *l)
{
	LuaCheckArgs(l, 1);
	const CUnitType *type = CclGetUnitType(l);
	const int *unit_types_count = AiPlayer->Player->UnitTypesAiActiveCount;
	const AiRequestType *autt = FindInUnitTypeRequests(type);
	if (!autt) {
		// Look if we have this unit-type.
		if (unit_types_count[type->Slot]) {
			lua_pushboolean(l, 0);
			return 1;
		}

		// Look if we have equivalent unit-types.
		if (type->Slot < (int)AiHelpers.Equiv().size()) {
			for (size_t j = 0; j < AiHelpers.Equiv()[type->Slot].size(); ++j) {
				if (unit_types_count[AiHelpers.Equiv()[type->Slot][j]->Slot]) {
					lua_pushboolean(l, 0);
					return 1;
				}
			}
		}
		// Look if we have an upgrade-to request.
		if (FindInUpgradeToRequests(type)) {
			lua_pushboolean(l, 1);
			return 1;
		}
		DebugPrint("Broken? waiting on %s which wasn't requested.\n" _C_ type->Ident.c_str());
		lua_pushboolean(l, 0);
		return 1;
	}
	//
	// Add equivalent units
	//
	unsigned int n = unit_types_count[type->Slot];
	if (type->Slot < (int)AiHelpers.Equiv().size()) {
		for (size_t j = 0; j < AiHelpers.Equiv()[type->Slot].size(); ++j) {
			n += unit_types_count[AiHelpers.Equiv()[type->Slot][j]->Slot];
		}
	}
	// units available?
	if (n >= autt->Count) {
		lua_pushboolean(l, 0);
		return 1;
	}
	lua_pushboolean(l, 1);
	return 1;
}

AiGetPendingBuilds


Get number of active build requests for a unit type.

@param l Lua State.

@return Number of return values

/ai/script_ai.cpp:837 CclAiPendingBuildCount

static int CclAiPendingBuildCount(lua_State *l)
{
	LuaCheckArgs(l, 1);
	const CUnitType *type = CclGetUnitType(l);

	// The assumption of this function is that UnitTypeBuilt will be always be
	// fairly small so we iterate each time instead of doing any caching
	for (auto b : AiPlayer->UnitTypeBuilt) {
		if (b.Type == type) {
			lua_pushinteger(l, b.Want);
			return 1;
		}
	}
	lua_pushinteger(l, 0);
	return 1;
}

AiForce


Description

Define a force, a groups of units.

@param l Lua state.

Example:

local simple_ai_loop = {
-- Sleep for 5 in game minutes
function() return AiSleep(9000) end,
-- Repeat the instructions forever.
function() stratagus.gameData.AIState.loop_index[1 + AiPlayer()] = 0; return false; end,
}

local simple_ai = {
function() return AiSleep(AiGetSleepCycles()) end,
-- Tell to the A.I that it needs a Town Hall.
function() return AiNeed("unit-town-hall") end,
-- Wait until the Town Hall has been built.
function() return AiWait("unit-town-hall") end,
-- Tell to the A.I that it needs 4 peasants
function() return AiSet("unit-peasant",4) end,
-- Tell to the A.I that it needs a Barracks.
function() return AiNeed("unit-human-barracks") end,
-- Tell to the A.I that it needs a Lumbermill.
function() return AiNeed("unit-elven-lumber-mill") end,
-- Wait until the Barracks has been built.
function() return AiWait("unit-human-barracks") end,
-- Wait until the Lumbermill has been built.
function() return AiWait("unit-elven-lumber-mill") end,
-- Specify the force number 1 made only of 3 footmen
function() return AiForce(1,{"unit-footman", 3}) end,
-- Specify the force number 2 made only of 2 archers
function() return AiForce(2,{"unit-archer", 2}) end,
-- Specify the force number 3 made of 2 footmen and 1 archer
function() return AiForce(3,{"unit-footman", 2, "unit-archer", 1}) end,
-- Wait for all three forces
function() return AiWaitForce(1) end,
function() return AiWaitForce(2) end,
function() return AiWaitForce(3) end,
-- Execute the instructions in simple_ai_loop
function() return AiLoop(simple_ai_loop, stratagus.gameData.AIState.loop_index) end,
}

function custom_ai() return AiLoop(simple_ai,stratagus.gameData.AIState.index) end
DefineAi("example_ai","human","class_ai",custom_ai)

/ai/script_ai.cpp:959 CclAiForce

static int CclAiForce(lua_State *l)
{
	bool resetForce = false;
	const int arg = lua_gettop(l);
	Assert(0 < arg && arg <= 3);
	if (!lua_istable(l, 2)) {
		LuaError(l, "incorrect argument");
	}
	if (arg == 3) {
		resetForce = LuaToBoolean(l, 3);
	}
	int force = LuaToNumber(l, 1);
	if (force < 0 || force >= AI_MAX_FORCE_INTERNAL) {
		LuaError(l, "Force out of range: %d" _C_ force);
	}
	AiForce &aiforce = AiPlayer->Force[AiPlayer->Force.getScriptForce(force)];
	if (resetForce) {
		aiforce.Reset(true);
	}
	AiForceRole role = aiforce.Role;
	aiforce.State = AiForceAttackingState_Waiting;
	aiforce.Role = role;

	int args = lua_rawlen(l, 2);
	for (int j = 0; j < args; ++j) {
		lua_rawgeti(l, 2, j + 1);
		CUnitType *type = CclGetUnitType(l);
		lua_pop(l, 1);
		++j;
		int count = LuaToNumber(l, 2, j + 1);

		if (!type) { // bulletproof
			continue;
		}

		// Use the equivalent unittype.
		type = UnitTypes[UnitTypeEquivs[type->Slot]];

		if (resetForce) {
			// Append it.
			AiUnitType newaiut;
			newaiut.Want = count;
			newaiut.Type = type;
			aiforce.UnitTypes.push_back(newaiut);
		} else {
			// Look if already in force.
			size_t i;
			for (i = 0; i < aiforce.UnitTypes.size(); ++i) {
				AiUnitType *aiut = &aiforce.UnitTypes[i];
				if (aiut->Type->Slot == type->Slot) { // found
					if (count) {
						aiut->Want = count;
					} else {
						aiforce.UnitTypes.erase(aiforce.UnitTypes.begin() + i);
					}
					break;
				}
			}
			// New type append it.
			if (i == aiforce.UnitTypes.size()) {
				AiUnitType newaiut;
				newaiut.Want = count;
				newaiut.Type = type;
				aiforce.UnitTypes.push_back(newaiut);
			}
		}

	}
	AiAssignFreeUnitsToForce(force);
	lua_pushboolean(l, 0);
	return 1;
}

AiReleaseForce


Release force.

@param l Lua state.

/ai/script_ai.cpp:1044 CclAiReleaseForce

static int CclAiReleaseForce(lua_State *l)
{
	LuaCheckArgs(l, 1);
	int force = LuaToNumber(l, 1);
	if (force < 0 || force >= AI_MAX_FORCE_INTERNAL) {
		LuaError(l, "Force out of range: %d" _C_ force);
	}
	for (int i = AI_MAX_FORCE_INTERNAL; i < AI_MAX_FORCES; ++i) {
		if (AiPlayer->Force[i].FormerForce != -1 && AiPlayer->Force[i].FormerForce == force) {
			while (AiPlayer->Force[i].Size()) {
				CUnit &aiunit = *AiPlayer->Force[i].Units[AiPlayer->Force[i].Size() - 1];
				aiunit.GroupId = 0;
				AiPlayer->Force[i].Units.Remove(&aiunit);
			}
			AiPlayer->Force[i].Reset(false);
		}
	}

	lua_pushboolean(l, 0);
	return 1;
}

AiForceRole


Description

Define the role of a force.

@param l Lua state.

Example:

local simple_ai_loop = {
function() return AiSleep(9000) end,
function() stratagus.gameData.AIState.loop_index[1 + AiPlayer()] = 0; return false; end,
}

local simple_ai = {
function() return AiSleep(AiGetSleepCycles()) end,
function() return AiNeed("unit-town-hall") end,
function() return AiWait("unit-town-hall") end,
function() return AiSet("unit-peasant",4) end,
function() return AiNeed("unit-human-barracks") end,
function() return AiNeed("unit-elven-lumber-mill") end,
-- Force 1 has the role of attacker
function() return AiForceRole(1,"attack") end,
-- Force 2 has the role of defender
function() return AiForceRole(2,"defend") end,
function() return AiForce(1,{"unit-footman", 3}) end,
function() return AiForce(2,{"unit-archer", 2}) end,
function() return AiWaitForce(1) end,
function() return AiWaitForce(2) end,
-- Execute the instructions in simple_ai_loop
function() return AiLoop(simple_ai_loop, stratagus.gameData.AIState.loop_index) end,
}

function custom_ai() return AiLoop(simple_ai,stratagus.gameData.AIState.index) end
DefineAi("example_ai","human","class_ai",custom_ai)

/ai/script_ai.cpp:1017 CclAiForceRole

static int CclAiForceRole(lua_State *l)
{
	LuaCheckArgs(l, 2);
	int force = LuaToNumber(l, 1);
	if (force < 0 || force >= AI_MAX_FORCE_INTERNAL) {
		LuaError(l, "Force %i out of range" _C_ force);
	}

	AiForce &aiforce = AiPlayer->Force[AiPlayer->Force.getScriptForce(force)];

	const char *flag = LuaToString(l, 2);
	if (!strcmp(flag, "attack")) {
		aiforce.Role = AiForceRoleAttack;
	} else if (!strcmp(flag, "defend")) {
		aiforce.Role = AiForceRoleDefend;
	} else {
		LuaError(l, "Unknown force role '%s'" _C_ flag);
	}
	lua_pushboolean(l, 0);
	return 1;
}

AiCheckForce


Check if a force ready.

@param l Lua state.

/ai/script_ai.cpp:1064 CclAiCheckForce

static int CclAiCheckForce(lua_State *l)
{
	LuaCheckArgs(l, 1);
	int force = LuaToNumber(l, 1);
	if (force < 0 || force >= AI_MAX_FORCE_INTERNAL) {
		lua_pushfstring(l, "Force out of range: %d", force);
	}
	if (AiPlayer->Force[AiPlayer->Force.getScriptForce(force)].Completed) {
		lua_pushboolean(l, 1);
		return 1;
	}
	lua_pushboolean(l, 0);
	return 1;
}

AiWaitForce


Description

Wait for a force ready.

@param l Lua state.

Example:

local simple_ai_loop = {
function() return AiSleep(9000) end,
function() stratagus.gameData.AIState.loop_index[1 + AiPlayer()] = 0; return false; end,
}

local simple_ai = {
function() return AiSleep(AiGetSleepCycles()) end,
function() return AiNeed("unit-town-hall") end,
function() return AiWait("unit-town-hall") end,
function() return AiSet("unit-peasant",4) end,
function() return AiNeed("unit-human-barracks") end,
function() return AiWait("unit-human-barracks") end,
function() return AiForce(1,{"unit-footman", 3}) end,
-- Wait until force 1 is completed
function() return AiWaitForce(1) end,
function() return AiLoop(simple_ai_loop, stratagus.gameData.AIState.loop_index) end,
}

function custom_ai() return AiLoop(simple_ai,stratagus.gameData.AIState.index) end
DefineAi("example_ai","human","class_ai",custom_ai)

/ai/script_ai.cpp:1114 CclAiWaitForce

static int CclAiWaitForce(lua_State *l)
{
	LuaCheckArgs(l, 1);
	int force = LuaToNumber(l, 1);
	if (force < 0 || force >= AI_MAX_FORCE_INTERNAL) {
		lua_pushfstring(l, "Force out of range: %d", force);
	}
	if (AiPlayer->Force[AiPlayer->Force.getScriptForce(force)].Completed) {
		lua_pushboolean(l, 0);
		return 1;
	}
#if 0
	// Debuging
	AiRemoveDeadUnitInForces();
	Assert(!AiPlayer->Force.getScriptForce(f).Completed);
#endif
	lua_pushboolean(l, 1);
	return 1;
}

AiAttackWithForce


Description

Attack with one single force.

@param l Lua state.

Example:

local simple_ai_loop = {
function() return AiSleep(9000) end,
function() stratagus.gameData.AIState.loop_index[1 + AiPlayer()] = 0; return false; end,
}

local simple_ai = {
function() return AiSleep(AiGetSleepCycles()) end,
function() return AiNeed("unit-town-hall") end,
function() return AiWait("unit-town-hall") end,
function() return AiSet("unit-peasant",4) end,
function() return AiNeed("unit-human-barracks") end,
function() return AiWait("unit-human-barracks") end,
function() return AiForce(1,{"unit-footman", 3}) end,
function() return AiWaitForce(1) end,
-- Attack with Force 1
function() return AiAttackWithForce(1) end,

function() return AiForce(2,{"unit-footman",5}) end,
function() return AiWaitForce(2) end,
-- Attack with Force 2
function() return AiAttackWithForce(2) end,
function() return AiLoop(simple_ai_loop, stratagus.gameData.AIState.loop_index) end,
}

function custom_ai() return AiLoop(simple_ai,stratagus.gameData.AIState.index) end
DefineAi("example_ai","human","class_ai",custom_ai)

/ai/script_ai.cpp:1162 CclAiAttackWithForce

static int CclAiAttackWithForce(lua_State *l)
{
	LuaCheckArgs(l, 1);
	int force = LuaToNumber(l, 1);
	if (force < 0 || force >= AI_MAX_FORCE_INTERNAL) {
		LuaError(l, "Force out of range: %d" _C_ force);
	}
	AiAttackWithForce(force);
	lua_pushboolean(l, 0);
	return 1;
}

AiSleep


Description

Sleep for n cycles.

@param l Lua state.

Example:

local simple_ai_loop = {
-- Sleep for 5 in game minutes
function() return AiSleep(9000) end,
function() stratagus.gameData.AIState.loop_index[1 + AiPlayer()] = 0; return false; end,
}

local simple_ai = {
-- Get the number of cycles to sleep
function() return AiSleep(AiGetSleepCycles()) end,
function() return AiNeed("unit-town-hall") end,
function() return AiWait("unit-town-hall") end,
function() return AiSet("unit-peasant",4) end,
-- Sleep for 1 in game minute
function() return AiSleep(1800) end,
function() return AiNeed("unit-human-blacksmith") end,
function() return AiWait("unit-human-blacksmith") end,
function() return AiLoop(simple_ai_loop, stratagus.gameData.AIState.loop_index) end,
}

function custom_ai() return AiLoop(simple_ai,stratagus.gameData.AIState.index) end
DefineAi("example_ai","human","class_ai",custom_ai)

/ai/script_ai.cpp:1325 CclAiSleep

static int CclAiSleep(lua_State *l)
{
	LuaCheckArgs(l, 1);
	int i = LuaToNumber(l, 1);
	if (AiPlayer->SleepCycles || i == 0) {
		if (AiPlayer->SleepCycles < GameCycle) {
			AiPlayer->SleepCycles = 0;
			lua_pushboolean(l, 0);
			return 1;
		}
	} else {
		AiPlayer->SleepCycles = GameCycle + i;
	}
	lua_pushboolean(l, 1);
	return 1;
}

AiResearch


Description

Research an upgrade.

@param l Lua state.

Example:

local simple_ai_loop = {
function() return AiSleep(9000) end,
function() stratagus.gameData.AIState.loop_index[1 + AiPlayer()] = 0; return false; end,
}

local simple_ai = {
-- Get the number of cycles to sleep
function() return AiSleep(AiGetSleepCycles()) end,
function() return AiNeed("unit-town-hall") end,
function() return AiWait("unit-town-hall") end,
function() return AiSet("unit-peasant",4) end,
function() return AiNeed("unit-human-barracks") end,
function() return AiWait("unit-human-barracks") end,
function() return AiNeed("unit-elven-lumber-mill") end,
function() return AiWait("unit-elven-lumber-mill") end,
function() return AiForce(1,{"unit-footman", 1, "unit-archer", 2}) end,
function() return AiWaitForce(1) end,
-- Upgrade the archers arrow.
function() return AiResearch("upgrade-arrow1") end,
function() return AiLoop(simple_ai_loop, stratagus.gameData.AIState.loop_index) end,
}

function custom_ai() return AiLoop(simple_ai,stratagus.gameData.AIState.index) end
DefineAi("example_ai","human","class_ai",custom_ai)

/ai/script_ai.cpp:1376 CclAiResearch

static int CclAiResearch(lua_State *l)
{
	LuaCheckArgs(l, 1);
	const char *str = LuaToString(l, 1);
	CUpgrade *upgrade;

	if (str) {
		upgrade = CUpgrade::Get(str);
	} else {
		LuaError(l, "Upgrade needed");
		upgrade = NULL;
	}
	InsertResearchRequests(upgrade);
	lua_pushboolean(l, 0);
	return 1;
}

AiUpgradeTo


Description

Upgrade an unit to an new unit-type.

@param l Lua state.

Example:

local simple_ai_loop = {
function() return AiSleep(9000) end,
function() stratagus.gameData.AIState.loop_index[1 + AiPlayer()] = 0; return false; end,
}

local simple_ai = {
function() return AiSleep(AiGetSleepCycles()) end,
function() return AiNeed("unit-town-hall") end,
function() return AiWait("unit-town-hall") end,
function() return AiSet("unit-peasant",4) end,
function() return AiNeed("unit-human-barracks") end,
function() return AiWait("unit-human-barracks") end,
function() return AiNeed("unit-elven-lumber-mill") end,
function() return AiWait("unit-elven-lumber-mill") end,
function() return AiSleep(1800) end,
-- Upgrade the Town Hall to Keep
function() return AiUpgradeTo("unit-keep") end,
function() return AiWait("unit-keep") end,
function() return AiLoop(simple_ai_loop, stratagus.gameData.AIState.loop_index) end,
}

function custom_ai() return AiLoop(simple_ai,stratagus.gameData.AIState.index) end
DefineAi("example_ai","human","class_ai",custom_ai)

/ai/script_ai.cpp:1419 CclAiUpgradeTo

static int CclAiUpgradeTo(lua_State *l)
{
	LuaCheckArgs(l, 1);
	CUnitType *type = CclGetUnitType(l);
	InsertUpgradeToRequests(type);

	lua_pushboolean(l, 0);
	return 1;
}

AiPlayer


Return the player of the running AI.

@param l Lua state.

@return Player number of the AI.

/ai/script_ai.cpp:1433 CclAiPlayer

static int CclAiPlayer(lua_State *l)
{
	LuaCheckArgs(l, 0);
	lua_pushnumber(l, AiPlayer->Player->Index);
	return 1;
}

AiSetReserve


Set AI player resource reserve.

@param l Lua state.

@return Old resource vector

/ai/script_ai.cpp:1457 CclAiSetReserve

static int CclAiSetReserve(lua_State *l)
{
	LuaCheckArgs(l, 1);
	if (!lua_istable(l, 1)) {
		LuaError(l, "incorrect argument");
	}
	lua_newtable(l);
	for (int i = 0; i < MaxCosts; ++i) {
		lua_pushnumber(l, AiPlayer->Reserve[i]);
		lua_rawseti(l, -2, i + 1);
	}
	for (int i = 0; i < MaxCosts; ++i) {
		AiPlayer->Reserve[i] = LuaToNumber(l, 1, i + 1);
	}
	return 1;
}

AiSetCollect


Description

Set AI player resource collect percent.

@param l Lua state.

Example:

local simple_ai_loop = {
function() return AiSleep(9000) end,
function() stratagus.gameData.AIState.loop_index[1 + AiPlayer()] = 0; return false; end,
}

local simple_ai = {
function() return AiSleep(AiGetSleepCycles()) end,
function() return AiNeed("unit-town-hall") end,
function() return AiWait("unit-town-hall") end,
-- The peasants will focus only on gathering gold
function() return AiSetCollect({0,100,0,0,0,0,0}) end,
function() return AiSet("unit-peasant",4) end,
function() return AiWait("unit-peasant") end,
function() return AiSleep(1800) end,
-- The peasants will now focus 50% on gathering gold and 50% on gathering lumber
function() return AiSetCollect({0,50,50,0,0,0,0}) end,
function() return AiLoop(simple_ai_loop, stratagus.gameData.AIState.loop_index) end,
}

function custom_ai() return AiLoop(simple_ai,stratagus.gameData.AIState.index) end
DefineAi("example_ai","human","class_ai",custom_ai)

/ai/script_ai.cpp:1500 CclAiSetCollect

static int CclAiSetCollect(lua_State *l)
{
	LuaCheckArgs(l, 1);
	if (!lua_istable(l, 1)) {
		LuaError(l, "incorrect argument");
	}
	for (int i = 0; i < MaxCosts; ++i) {
		AiPlayer->Collect[i] = LuaToNumber(l, 1, i + 1);
	}
	return 0;
}

AiSetBuildDepots


Set AI player build.

@param l Lua state.

/ai/script_ai.cpp:1515 CclAiSetBuildDepots

static int CclAiSetBuildDepots(lua_State *l)
{
	LuaCheckArgs(l, 1);
	if (!lua_isboolean(l, 1)) {
		LuaError(l, "incorrect argument");
	}
	AiPlayer->BuildDepots = LuaToBoolean(l, 1);
	return 0;
}

AiDump


Description

Dump some AI debug information.

@param l Lua state.

Example:

local simple_ai_loop = {
function() return AiSleep(3600) end,
-- Get the information from all the A.I players
function() return AiDump() end,
function() stratagus.gameData.AIState.loop_index[1 + AiPlayer()] = 0; return false; end,
}

local simple_ai = {
function() return AiSleep(AiGetSleepCycles()) end,
function() return AiNeed("unit-town-hall") end,
function() return AiWait("unit-town-hall") end,
function() return AiSet("unit-peasant",4) end,
function() return AiWait("unit-peasant") end,
function() return AiLoop(simple_ai_loop, stratagus.gameData.AIState.loop_index) end,
}

function custom_ai() return AiLoop(simple_ai,stratagus.gameData.AIState.index) end
DefineAi("example_ai","human","class_ai",custom_ai)

/ai/script_ai.cpp:1611 CclAiDump

static int CclAiDump(lua_State *l)
{
	LuaCheckArgs(l, 0);
	for (int p = 0; p < PlayerMax - 1; ++p) {
		CPlayer &aip = Players[p];
		if (aip.AiEnabled) {
			//
			// Script
			//

			printf("------\n");
			for (int i = 0; i < MaxCosts; ++i) {
				printf("%s(%4d, %4d/%4d) ", DefaultResourceNames[i].c_str(),
					   aip.Resources[i], aip.StoredResources[i], aip.MaxResources[i]);
			}
			printf("\n");
			printf("Player %d:", aip.Index);
#if 0
			gh_display(gh_car(AiPlayer->Script));
#endif
			//
			// Requests
			//
			size_t n = aip.Ai->UnitTypeRequests.size();
			printf("UnitTypeRequests(%u):\n", static_cast<unsigned int>(n));
			for (size_t i = 0; i < n; ++i) {
				printf("%s ", aip.Ai->UnitTypeRequests[i].Type->Ident.c_str());
			}
			printf("\n");
			n = aip.Ai->UpgradeToRequests.size();
			printf("UpgradeToRequests(%u):\n", static_cast<unsigned int>(n));
			for (size_t i = 0; i < n; ++i) {
				printf("%s ", aip.Ai->UpgradeToRequests[i]->Ident.c_str());
			}
			printf("\n");
			n = aip.Ai->ResearchRequests.size();
			printf("ResearchRequests(%u):\n", static_cast<unsigned int>(n));
			for (size_t i = 0; i < n; ++i) {
				printf("%s ", aip.Ai->ResearchRequests[i]->Ident.c_str());
			}
			printf("\n");

			// Building queue
			printf("Building queue:\n");
			for (size_t i = 0; i < aip.Ai->UnitTypeBuilt.size(); ++i) {
				const AiBuildQueue &queue = aip.Ai->UnitTypeBuilt[i];
				printf("%s(%d/%d) ", queue.Type->Ident.c_str(), queue.Made, queue.Want);
			}
			printf("\n");

			// PrintForce
			for (size_t i = 0; i < aip.Ai->Force.Size(); ++i) {
				printf("Force(%u%s%s):\n", static_cast<unsigned int>(i),
					   aip.Ai->Force[i].Completed ? ",complete" : ",recruit",
					   aip.Ai->Force[i].Attacking ? ",attack" : "");
				for (size_t j = 0; j < aip.Ai->Force[i].UnitTypes.size(); ++j) {
					const AiUnitType &aut = aip.Ai->Force[i].UnitTypes[j];
					printf("%s(%d) ", aut.Type->Ident.c_str(), aut.Want);
				}
				printf("\n");
			}
			printf("\n");
		}
	}
	lua_pushboolean(l, 0);
	return 1;
}

DefineAiPlayer


Define an AI player.

@param l Lua state.

/ai/script_ai.cpp:1899 CclDefineAiPlayer

static int CclDefineAiPlayer(lua_State *l)
{
	const unsigned int playerIdx = LuaToNumber(l, 0 + 1);

	Assert(playerIdx <= PlayerMax);
	DebugPrint("%p %d\n" _C_(void *)Players[playerIdx].Ai _C_ Players[playerIdx].AiEnabled);
	// FIXME: lose this:
	// Assert(!Players[playerIdx].Ai && Players[playerIdx].AiEnabled);

	PlayerAi *ai = Players[playerIdx].Ai = new PlayerAi;
	ai->Player = &Players[playerIdx];

	// Parse the list: (still everything could be changed!)
	const int args = lua_gettop(l);
	for (int j = 1; j < args; ++j) {
		const char *value = LuaToString(l, j + 1);
		++j;

		if (!strcmp(value, "ai-type")) {
			const char *aiName = LuaToString(l, j + 1);
			CAiType *ait = GetAiTypesByName(aiName);
			if (ait == NULL) {
				LuaError(l, "ai-type not found: %s" _C_ aiName);
			}
			ai->AiType = ait;
			ai->Script = ait->Script;
		} else if (!strcmp(value, "script")) {
			ai->Script = LuaToString(l, j + 1);
		} else if (!strcmp(value, "script-debug")) {
			ai->ScriptDebug = LuaToBoolean(l, j + 1);
		} else if (!strcmp(value, "sleep-cycles")) {
			ai->SleepCycles = LuaToNumber(l, j + 1);
		} else if (!strcmp(value, "force")) {
			if (!lua_istable(l, j + 1)) {
				LuaError(l, "incorrect argument");
			}
			const int subargs = lua_rawlen(l, j + 1);
			const int cclforceIdx = LuaToNumber(l, j + 1, 1);
			UNUSED(cclforceIdx);
			const int forceIdx = ai->Force.FindFreeForce(AiForceRoleDefault);

			for (int k = 1; k < subargs; ++k) {
				const char *value = LuaToString(l, j + 1, k + 1);
				++k;
				if (!strcmp(value, "complete")) {
					ai->Force[forceIdx].Completed = true;
					--k;
				} else if (!strcmp(value, "recruit")) {
					ai->Force[forceIdx].Completed = false;
					--k;
				} else if (!strcmp(value, "attack")) {
					ai->Force[forceIdx].Attacking = true;
					--k;
				} else if (!strcmp(value, "defend")) {
					ai->Force[forceIdx].Defending = true;
					--k;
				} else if (!strcmp(value, "role")) {
					value = LuaToString(l, j + 1, k + 1);
					if (!strcmp(value, "attack")) {
						ai->Force[forceIdx].Role = AiForceRoleAttack;
					} else if (!strcmp(value, "defend")) {
						ai->Force[forceIdx].Role = AiForceRoleDefend;
					} else {
						LuaError(l, "Unsupported force tag: %s" _C_ value);
					}
				} else if (!strcmp(value, "types")) {
					lua_rawgeti(l, j + 1, k + 1);
					if (!lua_istable(l, -1)) {
						LuaError(l, "incorrect argument");
					}
					const int subsubargs = lua_rawlen(l, -1);
					for (int subk = 0; subk < subsubargs; ++subk) {
						const int num = LuaToNumber(l, -1, subk + 1);
						++subk;
						const char *ident = LuaToString(l, -1, subk + 1);
						AiUnitType queue;

						queue.Want = num;
						queue.Type = UnitTypeByIdent(ident);
						ai->Force[forceIdx].UnitTypes.push_back(queue);
					}
					lua_pop(l, 1);
				} else if (!strcmp(value, "units")) {
					lua_rawgeti(l, j + 1, k + 1);
					if (!lua_istable(l, -1)) {
						LuaError(l, "incorrect argument");
					}
					const int subsubargs = lua_rawlen(l, -1);
					for (int subk = 0; subk < subsubargs; ++subk) {
						const int num = LuaToNumber(l, -1, subk + 1);
						++subk;
#if 0
						const char *ident = LuaToString(l, -1, subk + 1);
						UNUSED(ident);
#endif
						ai->Force[forceIdx].Units.Insert(&UnitManager->GetSlotUnit(num));
					}
					lua_pop(l, 1);
				} else if (!strcmp(value, "state")) {
					ai->Force[forceIdx].State = AiForceAttackingState(LuaToNumber(l, j + 1, k + 1));
				} else if (!strcmp(value, "goalx")) {
					ai->Force[forceIdx].GoalPos.x = LuaToNumber(l, j + 1, k + 1);
				} else if (!strcmp(value, "goaly")) {
					ai->Force[forceIdx].GoalPos.y = LuaToNumber(l, j + 1, k + 1);
				} else if (!strcmp(value, "must-transport")) {
					// Keep for backward compatibility
				} else {
					LuaError(l, "Unsupported tag: %s" _C_ value);
				}
			}
		} else if (!strcmp(value, "reserve")) {
			if (!lua_istable(l, j + 1)) {
				LuaError(l, "incorrect argument");
			}
			const int subargs = lua_rawlen(l, j + 1);
			for (int k = 0; k < subargs; ++k) {
				const char *type = LuaToString(l, j + 1, k + 1);
				++k;
				int num = LuaToNumber(l, j + 1, k + 1);
				const int resId = GetResourceIdByName(l, type);
				ai->Reserve[resId] = num;
			}
		} else if (!strcmp(value, "used")) {
			if (!lua_istable(l, j + 1)) {
				LuaError(l, "incorrect argument");
			}
			const int subargs = lua_rawlen(l, j + 1);
			for (int k = 0; k < subargs; ++k) {
				const char *type = LuaToString(l, j + 1, k + 1);
				++k;
				const int num = LuaToNumber(l, j + 1, k + 1);
				const int resId = GetResourceIdByName(l, type);
				ai->Used[resId] = num;
			}
		} else if (!strcmp(value, "needed")) {
			if (!lua_istable(l, j + 1)) {
				LuaError(l, "incorrect argument");
			}
			const int subargs = lua_rawlen(l, j + 1);
			for (int k = 0; k < subargs; ++k) {
				const char *type = LuaToString(l, j + 1, k + 1);
				++k;
				const int num = LuaToNumber(l, j + 1, k + 1);
				const int resId = GetResourceIdByName(l, type);
				ai->Needed[resId] = num;
			}
		} else if (!strcmp(value, "collect")) {
			if (!lua_istable(l, j + 1)) {
				LuaError(l, "incorrect argument");
			}
			const int subargs = lua_rawlen(l, j + 1);
			for (int k = 0; k < subargs; ++k) {
				const char *type = LuaToString(l, j + 1, k + 1);
				++k;
				const int num = LuaToNumber(l, j + 1, k + 1);
				const int resId = GetResourceIdByName(l, type);
				ai->Collect[resId] = num;
			}
		} else if (!strcmp(value, "need-mask")) {
			if (!lua_istable(l, j + 1)) {
				LuaError(l, "incorrect argument");
			}
			const int subargs = lua_rawlen(l, j + 1);
			for (int k = 0; k < subargs; ++k) {
				const char *type = LuaToString(l, j + 1, k + 1);
				const int resId = GetResourceIdByName(l, type);
				ai->NeededMask |= (1 << resId);
			}
		} else if (!strcmp(value, "need-supply")) {
			ai->NeedSupply = true;
			--j;
		} else if (!strcmp(value, "exploration")) {
			if (!lua_istable(l, j + 1)) {
				LuaError(l, "incorrect argument");
			}
			const int subargs = lua_rawlen(l, j + 1);
			for (int k = 0; k < subargs; ++k) {
				Vec2i pos;

				lua_rawgeti(l, j + 1, k + 1);
				if (!lua_istable(l, -1) || lua_rawlen(l, -1) != 3) {
					LuaError(l, "incorrect argument");
				}
				pos.x = LuaToNumber(l, -1, 1);
				pos.y = LuaToNumber(l, -1, 2);
				const int mask = LuaToNumber(l, -1, 3);
				lua_pop(l, 1);
				AiExplorationRequest queue(pos, mask);
				ai->FirstExplorationRequest.push_back(queue);
			}
		} else if (!strcmp(value, "last-exploration-cycle")) {
			ai->LastExplorationGameCycle = LuaToNumber(l, j + 1);
		} else if (!strcmp(value, "last-can-not-move-cycle")) {
			ai->LastCanNotMoveGameCycle = LuaToNumber(l, j + 1);
		} else if (!strcmp(value, "unit-type")) {
			if (!lua_istable(l, j + 1)) {
				LuaError(l, "incorrect argument");
			}
			const int subargs = lua_rawlen(l, j + 1);
			int i = 0;
			if (subargs) {
				ai->UnitTypeRequests.resize(subargs / 2);
			}
			for (int k = 0; k < subargs; ++k) {
				const char *ident = LuaToString(l, j + 1, k + 1);
				++k;
				const int count = LuaToNumber(l, j + 1, k + 1);
				ai->UnitTypeRequests[i].Type = UnitTypeByIdent(ident);
				ai->UnitTypeRequests[i].Count = count;
				++i;
			}
		} else if (!strcmp(value, "upgrade")) {
			if (!lua_istable(l, j + 1)) {
				LuaError(l, "incorrect argument");
			}
			const int subargs = lua_rawlen(l, j + 1);
			for (int k = 0; k < subargs; ++k) {
				const char *ident = LuaToString(l, j + 1, k + 1);
				ai->UpgradeToRequests.push_back(UnitTypeByIdent(ident));
			}
		} else if (!strcmp(value, "research")) {
			if (!lua_istable(l, j + 1)) {
				LuaError(l, "incorrect argument");
			}
			const int subargs = lua_rawlen(l, j + 1);
			for (int k = 0; k < subargs; ++k) {
				const char *ident = LuaToString(l, j + 1, k + 1);
				ai->ResearchRequests.push_back(CUpgrade::Get(ident));
			}
		} else if (!strcmp(value, "building")) {
			CclParseBuildQueue(l, ai, j + 1);
		} else if (!strcmp(value, "repair-building")) {
			ai->LastRepairBuilding = LuaToNumber(l, j + 1);
		} else {
			LuaError(l, "Unsupported tag: %s" _C_ value);
		}
	}
	return 0;
}

AiAttackWithForces


Description

Attack with forces.

@param l Lua state.

Example:

local simple_ai_loop = {
function() return AiSleep(9000) end,
function() stratagus.gameData.AIState.loop_index[1 + AiPlayer()] = 0; return false; end,
}

local simple_ai = {
function() return AiSleep(AiGetSleepCycles()) end,
function() return AiNeed("unit-town-hall") end,
function() return AiWait("unit-town-hall") end,
function() return AiSet("unit-peasant",4) end,
function() return AiNeed("unit-human-barracks") end,
function() return AiWait("unit-human-barracks") end,
function() return AiNeed("unit-elven-lumber-mill") end,
function() return AiWait("unit-elven-lumber-mill") end,
function() return AiForce(1,{"unit-footman", 2}) end,
function() return AiForce(2,{"unit-archer",1}) end,
function() return AiForce(3,{"unit-archer",1,"unit-footman",3}) end,
-- Wait all three forces to be ready
function() return AiWaitForces({1,2,3}) end,
-- Attack with all three forces
function() return AiAttackWithForces({1,2,3}) end,
function() return AiLoop(simple_ai_loop, stratagus.gameData.AIState.loop_index) end,
}

function custom_ai() return AiLoop(simple_ai,stratagus.gameData.AIState.index) end
DefineAi("example_ai","human","class_ai",custom_ai)

/ai/script_ai.cpp:1277 CclAiAttackWithForces

static int CclAiAttackWithForces(lua_State *l)
{
	int Forces[AI_MAX_FORCE_INTERNAL + 1];

	LuaCheckArgs(l, 1);
	if (!lua_istable(l, 1)) {
		LuaError(l, "incorrect argument");
	}
	int args = lua_rawlen(l, 1);
	for (int i = 0; i < args; ++i) {
		const int force = LuaToNumber(l, 1, i + 1);

		if (force < 0 || force >= AI_MAX_FORCE_INTERNAL) {
			lua_pushfstring(l, "Force out of range: %d", force);
		}
		Forces[i] = AiPlayer->Force.getScriptForce(force);
	}
	Forces[args] = -1;
	AiAttackWithForces(Forces);
	lua_pushboolean(l, 0);
	return 1;
}

AiWaitForces


Description

Wait for a forces ready.

@param l Lua state.

Example:

local simple_ai_loop = {
function() return AiSleep(9000) end,
function() stratagus.gameData.AIState.loop_index[1 + AiPlayer()] = 0; return false; end,
}

local simple_ai = {
function() return AiSleep(AiGetSleepCycles()) end,
function() return AiNeed("unit-town-hall") end,
function() return AiWait("unit-town-hall") end,
function() return AiSet("unit-peasant",4) end,
function() return AiNeed("unit-human-barracks") end,
function() return AiWait("unit-human-barracks") end,
function() return AiNeed("unit-elven-lumber-mill") end,
function() return AiWait("unit-elven-lumber-mill") end,
function() return AiForce(1,{"unit-footman", 2}) end,
function() return AiForce(2,{"unit-archer",1}) end,
function() return AiForce(3,{"unit-archer",1,"unit-footman",3}) end,
-- Wait all three forces to be ready
function() return AiWaitForces({1,2,3}) end,
function() return AiLoop(simple_ai_loop, stratagus.gameData.AIState.loop_index) end,
}

function custom_ai() return AiLoop(simple_ai,stratagus.gameData.AIState.index) end
DefineAi("example_ai","human","class_ai",custom_ai)

/ai/script_ai.cpp:1218 CclAiWaitForces

static int CclAiWaitForces(lua_State *l)
{
	LuaCheckArgs(l, 1);
	if (!lua_istable(l, 1)) {
		LuaError(l, "incorrect argument");
	}
	const int args = lua_rawlen(l, 1);
	for (int i = 0; i < args; ++i) {
		const int force = LuaToNumber(l, 1, i + 1);

		if (force < 0 || force >= AI_MAX_FORCE_INTERNAL) {
			lua_pushfstring(l, "Force out of range: %d", force);
		}
		if (!AiPlayer->Force[AiPlayer->Force.getScriptForce(force)].Completed) {
			lua_pushboolean(l, 1);
			return 1;
		}
	}
	lua_pushboolean(l, 0);
	return 1;
}

AiProcessorSetup


AiProcessorSetup(host, port, number_of_state_variables, number_of_actions)

Connect to an AI agent running at host:port, that will consume
number_of_state_variables every step and select one of number_of_actions.

/ai/script_ai.cpp:1932 CclAiProcessorSetup

static int CclAiProcessorSetup(lua_State *l)
{
	InitNetwork1();
	LuaCheckArgs(l, 4);
	std::string host = LuaToString(l, 1);
	int port = LuaToNumber(l, 2);
	int stateDim = LuaToNumber(l, 3);
	int actionDim = LuaToNumber(l, 4);

	CHost h(host.c_str(), port);
	CTCPSocket *s = new CTCPSocket();
	s->Open(CHost());
	if (s->Connect(h)) {
		char buf[3];
		buf[0] = 'I';
		buf[1] = (uint8_t)stateDim;
		buf[2] = (uint8_t)actionDim;
		s->Send(buf, 3);
		lua_pushlightuserdata(l, s);
		return 1;
	}

	delete s;
	lua_pushnil(l);
	return 1;
}

AiProcessorStep


AiProcessorStep(handle, reward_since_last_call, table_of_state_variables)

/ai/script_ai.cpp:1987 CclAiProcessorStep

static int CclAiProcessorStep(lua_State *l)
{
	// A single step in a reinforcement learning network

	// We receive the current env and current reward in the arguments

	// We need to return the next action.

	// The next call to this function will be the updated state, reward for the
	// last action

	CTCPSocket *s = AiProcessorSendState(l, 'S');
	int action = 0;
	s->Recv(&action, 1);
	lua_pushnumber(l, action + 1); // +1 since lua tables are 1-indexed
	return 1;
}

AiProcessorEnd

/ai/script_ai.cpp:1995 CclAiProcessorEnd

static int CclAiProcessorEnd(lua_State *l)
{
	CTCPSocket *s = AiProcessorSendState(l, 'E');
	s->Close();
	delete s;
	return 0;
}


/editor/script_editor.cpp
SetEditorSelectIcon


Set the editor's select icon

@param l Lua state.

/editor/script_editor.cpp:59 CclSetEditorSelectIcon

static int CclSetEditorSelectIcon(lua_State *l)
{
	LuaCheckArgs(l, 1);
	Editor.Select.Name = LuaToString(l, 1);
	return 0;
}

SetEditorUnitsIcon


Set the editor's units icon

@param l Lua state.

/editor/script_editor.cpp:71 CclSetEditorUnitsIcon

static int CclSetEditorUnitsIcon(lua_State *l)
{
	LuaCheckArgs(l, 1);
	Editor.Units.Name = LuaToString(l, 1);
	return 0;
}

SetEditorStartUnit


Set the editor's start location unit

@param l Lua state.

/editor/script_editor.cpp:83 CclSetEditorStartUnit

static int CclSetEditorStartUnit(lua_State *l)
{
	LuaCheckArgs(l, 1);
	Editor.StartUnitName = LuaToString(l, 1);
	return 0;
}

EditorResizeMap

/editor/script_editor.cpp:93 CclEditorResizeMap

static int CclEditorResizeMap(lua_State *l)
{
	LuaCheckArgs(l, 5);
	int res = EditorSaveMapWithResize(LuaToString(l, 1),
							{(short)LuaToNumber(l, 2), (short)LuaToNumber(l, 3)},
							{(short)LuaToNumber(l, 4), (short)LuaToNumber(l, 5)});
	lua_pushnumber(l, res);
	return 1;
}

SetEditorRandomizeProperties


Confgure the randomize map feature of the editor.

@param l Lua state.

/editor/script_editor.cpp:149 CclEditorRandomizeProperties

static int CclEditorRandomizeProperties(lua_State *l)
{
	LuaCheckArgs(l, 1);
	if (!lua_istable(l, 1)) {
		LuaError(l, "incorrect argument");
	}

	Editor.RandomTiles.clear();
	Editor.RandomUnits.clear();

	for (lua_pushnil(l); lua_next(l, 1); lua_pop(l, 1)) {
		const char *value = LuaToString(l, -2);
		if (!strcmp(value, "BaseTile")) {
			Editor.BaseTileIndex = LuaToNumber(l, -1);
		} else if (!strcmp(value, "RandomTiles")) {
			if (!lua_istable(l, -1)) {
				LuaError(l, "incorrect argument");
			}
			int subargs = lua_rawlen(l, -1);
			for (int j = 0; j < subargs; j++) {
				lua_rawgeti(l, -1, j + 1);
				if (!lua_istable(l, -1)) {
					LuaError(l, "incorrect argument");
				}
				if (lua_rawlen(l, -1) != 3) {
					LuaError(l, "incorrect RandomTiles entry length, need 3 integers");
				}
				Editor.RandomTiles.push_back(std::make_tuple(LuaToNumber(l, -1, 1), LuaToNumber(l, -1, 2), LuaToNumber(l, -1, 3)));
				lua_pop(l, 1);
			}
		} else if (!strcmp(value, "RandomUnits")) {
			if (!lua_istable(l, -1)) {
				LuaError(l, "incorrect argument");
			}
			int subargs = lua_rawlen(l, -1);
			for (int j = 0; j < subargs; j++) {
				lua_rawgeti(l, -1, j + 1);
				if (!lua_istable(l, -1)) {
					LuaError(l, "incorrect argument");
				}
				if (lua_rawlen(l, -1) != 4) {
					LuaError(l, "incorrect RandomUnits entry length, need 1 string followed by 3 integers");
				}
				Editor.RandomUnits.push_back(std::make_tuple(std::string(LuaToString(l, -1, 1)), LuaToNumber(l, -1, 2), LuaToNumber(l, -1, 3), LuaToNumber(l, -1, 4)));
				lua_pop(l, 1);
			}
		}
	}
	return 0;
}


/network/netconnect.cpp
NoRandomPlacementMultiplayer


Controls Randomization of Player position in Multiplayer mode.
Without arguments, disables randomization. Otherwise, sets the
NoRandomization flag to the boolean argument value.

@param l Lua state.

/network/netconnect.cpp:2060 CclNoRandomPlacementMultiplayer

static int CclNoRandomPlacementMultiplayer(lua_State *l)
{
	int nargs = lua_gettop(l);
	if (nargs > 1) {
		LuaError(l, "incorrect argument");
	}
	bool flag = nargs ? LuaToBoolean(l, 1) : false;
	NoRandomPlacementMultiplayer = flag;
	return 0;
}

UsesRandomPlacementMultiplayer


Return if player positions in multiplayer mode are randomized.

@param l Lua state.

/network/netconnect.cpp:2072 CclUsesRandomPlacementMultiplayer

static int CclUsesRandomPlacementMultiplayer(lua_State *l)
{
	LuaCheckArgs(l, 0);
	lua_pushboolean(l, !NoRandomPlacementMultiplayer);
	return 1;
}

NetworkDiscoverServers

/network/netconnect.cpp:2092 CclNetworkDiscoverServers

static int CclNetworkDiscoverServers(lua_State *l)
{
	LuaCheckArgs(l, 1);
	bool start = LuaToBoolean(l, 1);

	auto callback= [l](char* ip) {
		auto i = lua_objlen(l, -1) + 1;
		lua_pushnumber(l, i);
		lua_pushstring(l, ip);
		lua_settable(l, -3);
	};

	lua_newtable(l);
	if (start) {
		MdnsService.QueryServers(callback);
	}

	return 1;
}


/tolua/game.pkg
bool IsReplayGame()

StartMap(const string str, bool clean = true)

StartReplay(const string str, bool reveal = false)

StartSavedGame(const string str)

int SaveReplay(const std::string filename)

enum GameResults {

enum GameResults {
    GameNoResult,
    GameVictory,
    GameDefeat,
    GameDraw,
    GameQuitToMenu,
    GameRestart,
};

GameResults GameResult

StopGame(GameResults result)

bool GameRunning

SetGamePaused(bool paused)

bool GetGamePaused()

SetGameSpeed(int speed)

int GetGameSpeed()

bool GameObserve

bool GameEstablishing

unsigned long GameCycle

unsigned long FastForwardCycle

enum RevealTypes {

enum RevealTypes { 
	cNoRevelation, 
	cAllUnits, 
	cBuildingsOnly 
};

enum NetGameTypes {

enum NetGameTypes {
	SettingsSinglePlayerGame,
	SettingsMultiPlayerGame,
	Unset
};

class Settings {

class Settings {
	NetGameTypes NetGameType;

	SettingsPresets Presets[PlayerMax];

	int Resources;
	int NumUnits;
	int Opponents;
	int Difficulty;
	GameTypes GameType;
	FieldOfViewTypes FoV;
	MapRevealModes RevealMap;
	RevealTypes DefeatReveal;
	bool NoFogOfWar;
	bool Inside;
	bool AiExplores;
	bool SimplifiedAutoTargeting;
	int _Bitfield @ Flags;

	bool GetUserGameSetting(int i);
	void SetUserGameSetting(int i, bool v);
};

Settings GameSettings

enum MapRevealModes {

enum MapRevealModes {
	cHidden,
	cKnown,
	cExplored,
	cNumOfModes
};

enum FieldOfViewTypes {

enum FieldOfViewTypes {
	cShadowCasting,
	cSimpleRadial,
	NumOfTypes
};

enum GameTypes {

enum GameTypes {
	SettingsGameTypeMapDefault = SettingsPresetMapDefault,
	SettingsGameTypeMelee = 0,
	SettingsGameTypeFreeForAll,
	SettingsGameTypeTopVsBottom,
	SettingsGameTypeLeftVsRight,
	SettingsGameTypeManVsMachine,
	SettingsGameTypeManTeamVsMachine,
	SettingsGameTypeMachineVsMachine,
        SettingsGameTypeMachineVsMachineTraining,
};


/tolua/pathfinder.pkg
bool AStarKnowUnseenTerrain


/tolua/ai.pkg
AiAttackWithForceAt(unsigned int force, unsigned int x, unsigned int y)

/// Attack with force at position

AiAttackWithForce(unsigned int force)

/// Attack with force


/tolua/stratagus.pkg
int SaveGame(const std::string filename)

DeleteSaveGame(const std::string filename)

int SyncRand(void)

int SyncRand(int max)

bool CanAccessFile(const char *filename)

Exit(int err)

bool IsDebugEnabled


/tolua/video.pkg
InitVideo()

int PlayMovie(const std::string name)

ShowFullImage(const std::string name, unsigned int timeOutInSecond)

SaveMapPNG(const char *name)

class CVideo

class CVideo
{
public:
	int Width;
	int Height;
	int Depth;
	bool FullScreen;
	bool ResizeScreen(int width, int height);
};

CVideo Video

ToggleFullScreen(void)

class CGraphic

class CGraphic
{
public:
	static CGraphic *New(const std::string file, int w = 0, int h = 0);
	static CGraphic *ForceNew(const std::string file, int w = 0, int h = 0);
	static CGraphic *Get(const std::string file);
	static void Free(CGraphic *);
	void Load(bool grayscale = false);
	void Resize(int w, int h);
	void SetPaletteColor(int idx, int r, int g, int b);
	void OverlayGraphic(CGraphic *g, bool mask = false);
};

class CPlayerColorGraphic : public CGraphic

class CPlayerColorGraphic : public CGraphic
{
public:
	static CPlayerColorGraphic *New(const std::string file, int w = 0, int h = 0);
	static CPlayerColorGraphic *ForceNew(const std::string file, int w = 0, int h = 0);
	static CPlayerColorGraphic *Get(const std::string file);
};

class CColor {

class CColor {
	CColor(unsigned char r = 0, unsigned char g = 0, unsigned char b = 0,
		unsigned char a = 0);

	unsigned char R;
	unsigned char G;
	unsigned char B;
	unsigned char A;
};

SetColorCycleAll(bool value)

ClearAllColorCyclingRange()

AddColorCyclingRange(unsigned int startColorIndex, unsigned int endColorIndex)

unsigned int SetColorCycleSpeed(unsigned int speed)


/tolua/unittype.pkg
class CUnitType

class CUnitType
{
	std::string Ident;
	std::string Name;
	tolua_readonly int Slot;

	int MinAttackRange;
	int ClicksToExplode;

	int GivesResource;

	int TileWidth;
	int TileHeight;
};

CUnitType *UnitTypeByIdent(const std::string ident)

CUnitType *UnitTypeHumanWall

CUnitType *UnitTypeOrcWall

SetMapStat(std::string ident, std::string variable_key, int value, std::string variable_type)

SetMapSound(std::string ident, std::string sound, std::string sound_type, std::string sound_subtype = "")


/tolua/font.pkg
class CFont

class CFont
{
	static CFont *New(const std::string ident, CGraphic *g);
	static CFont *Get(const std::string ident);

	int Height();
	int Width(const std::string text);
};

class CFontColor

class CFontColor
{
	static CFontColor *New(const std::string ident);
	static CFontColor *Get(const std::string ident);

	SDL_Color Colors[MaxFontColors];
};


/tolua/trigger.pkg
int GetNumOpponents(int player)

int GetTimer()

ActionVictory()

ActionDefeat()

ActionDraw()

ActionSetTimer(int cycles, bool increasing)

ActionStartTimer()

ActionStopTimer()

SetTrigger(int trigger)


/tolua/editor.pkg
enum EditorRunningType {

enum EditorRunningType {
	EditorNotRunning = 0,    /// Not Running
	EditorStarted = 1,       /// Editor Enabled at all
	EditorCommandLine = 2,   /// Called from Command Line
	EditorEditing = 4,       /// Editor is fully running
};

class CEditor

class CEditor
{
	vector<string> UnitTypes;
	bool TerrainEditable;
	const CUnitType *StartUnit;
	bool WriteCompressedMaps;
	EditorRunningType Running;
	void CreateRandomMap(bool shuffleTranslitions) const;
};

CEditor Editor

StartEditor(const char *filename)

int EditorSaveMap(const std::string &file)


/tolua/map.pkg
class CMapInfo

class CMapInfo
{
	string Description;
	string Filename;
        string Preamble;
        string Postamble;
	int MapWidth;
	int MapHeight;
	PlayerTypes PlayerType[PlayerMax];
};

class CTileset

class CTileset
{
	string Name;
};

class CMap

class CMap
{
	CMapInfo Info;
	CTileset *Tileset;
};

CMap Map

SetTile(int tile, int w, int h, int value = 0)


/tolua/minimap.pkg
class CMinimap

class CMinimap
{
	int X;
	int Y;
	int W;
	int H;
	bool WithTerrain;
	bool ShowSelected;
	bool Transparent;
};


/tolua/network.pkg
InitNetwork1(void)

ExitNetwork1(void)

bool IsNetworkGame()

int NetworkSetupServerAddress(const std::string serveraddr, int port = 0)

NetworkInitClientConnect(void)

NetworkInitServerConnect(int openslots)

NetworkServerStartGame(void)

NetworkProcessClientRequest(void)

int GetNetworkState()

NetworkServerResyncClients(void)

NetworkDetachFromServer(void)

class ServerSetupStateRacesArray {

class ServerSetupStateRacesArray {
    int& operator[](int idx) { return p[idx].Race; }
    int& operator[](int idx) const { return p[idx].Race; }
};

enum SlotOption {

enum SlotOption {
	Available @ SlotAvailable,
	Computer @ SlotComputer,
	Closed @ SlotClosed,
};

class CServerSetup {

class CServerSetup {
	Settings ServerGameSettings;
	SlotOption CompOpt[PlayerMax];
	unsigned short Ready[PlayerMax]; // cannot use char since tolua interpret variable as string.
	tolua_property unsigned char ResourcesOption;
	tolua_property unsigned char UnitsOption;
	tolua_property unsigned char FogOfWar;
	tolua_property unsigned char Inside;
	tolua_property unsigned char RevealMap;
	tolua_property unsigned char GameTypeOption;
	tolua_property unsigned char Difficulty;
	tolua_property unsigned char Opponents;
        tolua_property tolua_readonly ServerSetupStateRacesArray *Race;
};

CServerSetup LocalSetupState

CServerSetup ServerSetupState

int NetLocalHostsSlot

CNetworkHost Hosts[PlayerMax]

string NetworkMapName

string NetworkMapFragmentName

NetworkGamePrepareGameSettings(void)


/tolua/translate.pkg
const char *Translate(const char *str)

AddTranslation(const char *str1, const char *str2)

LoadPO(const char *file)

SetTranslationsFiles(const char *stratagusfile, const char *gamefile)


/tolua/particle.pkg
class GraphicAnimation

class GraphicAnimation
{
	GraphicAnimation(CGraphic *g, int ticksPerFrame);
	virtual GraphicAnimation * clone();
};

class CParticle

class CParticle
{
	virtual CParticle* clone();
	void setDrawLevel(int value);
};

class StaticParticle : public CParticle

class StaticParticle : public CParticle
{
public:
	StaticParticle(CPosition position, GraphicAnimation *animation, int drawlevel = 0);
};

class CChunkParticle : public CParticle

class CChunkParticle : public CParticle
{
public:
	CChunkParticle(CPosition position, GraphicAnimation *smokeAnimation, GraphicAnimation *debrisAnimation, GraphicAnimation *destroyAnimation, int minVelocity = 0, int maxVelocity = 400, int minTrajectoryAngle = 77, int maxTTL = 0, int drawlevel = 0);
	int getSmokeDrawLevel() const;
	int getDestroyDrawLevel() const;
	void setSmokeDrawLevel(int value);
	void setDestroyDrawLevel(int value);
};

class CSmokeParticle : public CParticle

class CSmokeParticle : public CParticle
{
public:
	CSmokeParticle(CPosition position, GraphicAnimation *animation, float speedx = 0, float speedy = -22.0, int drawlevel = 0);
};

class CRadialParticle : public CParticle

class CRadialParticle : public CParticle
{
public:
	CRadialParticle(CPosition position, GraphicAnimation *smokeAnimation, int maxSpeed, int drawlevel = 0);
};

class CParticleManager

class CParticleManager
{
public:
	CParticleManager();
	~CParticleManager();

	void add(CParticle *particle);
};

CParticleManager ParticleManager


/tolua/player.pkg
enum PlayerTypes {

enum PlayerTypes {
	PlayerNeutral = 2,
	PlayerNobody  = 3,
	PlayerComputer = 4,
	PlayerPerson = 5,
	PlayerRescuePassive = 6,
	PlayerRescueActive = 7,
};

class CPlayer

class CPlayer
{
	int Index;
	string Name;

	PlayerTypes Type;
	int Race;
	string AiName;

	Vec2i StartPos;

	void SetStartView(const Vec2i &pos);

	int Resources[MaxCosts];
	int StoredResources[MaxCosts];
	int Incomes[MaxCosts];
	const int Revenue[MaxCosts];

	const int UnitTypesCount[UnitTypeMax];
	const int UnitTypesAiActiveCount[UnitTypeMax];
	bool AiEnabled;

	int NumBuildings;
	int Supply;
	int Demand;

	int UnitLimit;
	int BuildingLimit;
	int TotalUnitLimit;

	int Score;
	int TotalUnits;
	int TotalBuildings;
	int TotalResources[MaxCosts];
	int TotalRazings;
	int TotalKills;

	int SpeedResourcesHarvest[MaxCosts];
	int SpeedResourcesReturn[MaxCosts];
	int SpeedBuild;
	int SpeedTrain;
	int SpeedUpgrade;
	int SpeedResearch;

	CUnit& GetUnit(int index) const;
	int GetUnitCount() const;

	bool IsEnemy(const CPlayer &player) const;
	bool IsEnemy(const CUnit &unit) const;
	bool IsAllied(const CPlayer &player) const;
	bool IsAllied(const CUnit &unit) const;
	bool HasSharedVisionWith(const CPlayer &player) const;
	bool IsTeamed(const CPlayer &player) const;
	bool IsTeamed(const CUnit &unit) const;
};

CPlayer Players[PlayerMax]

CPlayer *ThisPlayer


/tolua/upgrade.pkg
class CUpgrade

class CUpgrade
{
  static CUpgrade *New(const std::string ident);
  static CUpgrade *Get(const std::string ident);

  std::string Name;
  int Costs[MaxCosts];
  CIcon *Icon;
};


/tolua/unit.pkg
class Vec2i

class Vec2i
{
	short int x;
	short int y;
};

class CUnit

class CUnit
{
	tolua_readonly Vec2i tilePos;

	tolua_readonly CUnitType *Type;
	tolua_readonly CPlayer *Player;
	CUnit *Goal;
	bool Active;
	int ResourcesHeld;
};

class CPreference

class CPreference
{
	bool ShowSightRange;
	bool ShowReactionRange;
	bool ShowAttackRange;
	bool ShowMessages;
	bool ShowNoSelectionStats;
	bool BigScreen;
	bool PauseOnLeave;
	tolua_property bool AiExplores;
	bool GrayscaleIcons;
	bool IconsShift;
	bool StereoSound;
	bool MineNotifications;
	bool DeselectInMine;
	bool NoStatusLineTooltips;
	tolua_property bool SimplifiedAutoTargeting;
	tolua_property bool AiChecksDependencies;
	bool HardwareCursor;
	bool SelectionRectangleIndicatesDamage;

        unsigned int FrameSkip;

	unsigned int ShowOrders;
	unsigned int ShowNameDelay;
	unsigned int ShowNameTime;
	unsigned int AutosaveMinutes;

	CGraphic *IconFrameG;
	CGraphic *PressedIconFrameG;
};

class CUnitManager

class CUnitManager
{
	CUnit &GetSlotUnit(int index) const;
};

CPreference Preference

CUnit *GetUnitUnderCursor()

int UnitNumber(CUnit &unit)


/tolua/sound.pkg
int GetEffectsVolume(void)

SetEffectsVolume(int volume)

int GetMusicVolume(void)

SetMusicVolume(int volume)

SetEffectsEnabled(bool enabled)

bool IsEffectsEnabled(void)

SetMusicEnabled(bool enabled)

bool IsMusicEnabled(void)

int PlayFile(const std::string name, LuaActionListener *listener = NULL)

int PlayMusic(const std::string name)

StopMusic()

bool IsMusicPlaying()

int SetChannelVolume(int channel, int volume)

SetChannelStereo(int channel, int stereo)

StopChannel(int channel)

StopAllChannels()


/tolua/ui.pkg
enum ViewportModeType {

enum ViewportModeType {
	VIEWPORT_SINGLE = 0,
	VIEWPORT_SPLIT_HORIZ,
	VIEWPORT_SPLIT_HORIZ3,
	VIEWPORT_SPLIT_VERT,
	VIEWPORT_QUAD
};

class LuaActionListener

class LuaActionListener
{
	LuaActionListener(lua_State *lua, lua_Object luaref);
};

class CUIButton

class CUIButton
{
	CUIButton();

	int X;
	int Y;
	string Text;
	ButtonStyle *Style;
	LuaActionListener *Callback;
};

class CMapArea

class CMapArea
{
	int X;
	int Y;
	int EndX;
	int EndY;
	int ScrollPaddingLeft;
	int ScrollPaddingRight;
	int ScrollPaddingTop;
	int ScrollPaddingBottom;
};

class CViewport

class CViewport
{
};

class CFiller

class CFiller
{
	CFiller();

	CGraphic *G;
	int X;
	int Y;
};

class vector

class vector
{
	TOLUA_TEMPLATE_BIND(T, CFiller, CUIButton, CUIUserButton, string)

	vector();
	~vector();

	const T& operator[](int index) const;
	T& operator[](int index);
	const T& at(int index) const;
	T& at(int index);

	const T& front() const;
	T& front();
	const T& back() const;
	T& back();

	void push_back(T val);
	void pop_back();

	void assign(int num, const T& val);
	void clear();
	bool empty() const;
	int size() const;
};

class CButtonPanel

class CButtonPanel
{
	int X;
	int Y;
	vector<CUIButton> Buttons;
	CColor AutoCastBorderColorRGB;
	bool ShowCommandKey;
};

class CPieMenu

class CPieMenu
{
	CGraphic *G;
	int MouseButton;
	int X[8];
	int Y[8];

	void SetRadius(int radius);
};

class CResourceInfo

class CResourceInfo
{
	CGraphic *G;
	int IconFrame;
	int IconX;
	int IconY;
	int IconWidth;
	int TextX;
	int TextY;
};

class CInfoPanel

class CInfoPanel
{
	CGraphic *G;
	int X;
	int Y;
};

class CUIUserButton

class CUIUserButton
{
	CUIUserButton(); 

	bool Clicked;
	CUIButton Button;
};

class CStatusLine

class CStatusLine
{
	void Set(const std::string status);
	const std::string &Get();
	void Clear();

	int Width;
	int TextX;
	int TextY;
	CFont *Font;
};

class CUITimer

class CUITimer
{
	int X;
	int Y;
	CFont *Font;
};

class CUserInterface

class CUserInterface
{
	string NormalFontColor;
	string ReverseFontColor;

	vector<CFiller> Fillers;

	CResourceInfo Resources[MaxResourceInfo];
	CInfoPanel InfoPanel;
	string DefaultUnitPortrait;
	CUIButton *SingleSelectedButton;

	vector<CUIButton> SelectedButtons;
	CFont *MaxSelectedFont;
	int MaxSelectedTextX;
	int MaxSelectedTextY;

	CUIButton *SingleTrainingButton;
	vector<CUIButton> TrainingButtons;
	CUIButton *UpgradingButton;
	CUIButton *ResearchingButton;
	vector<CUIButton> TransportingButtons;

        vector<string> LifeBarColorNames;
        vector<int> LifeBarPercents;
        int LifeBarYOffset;
		int LifeBarPadding;
        bool LifeBarBorder;

	CColor CompletedBarColorRGB;
	bool CompletedBarShadow;

	CButtonPanel ButtonPanel;

	CPieMenu PieMenu;

	CViewport *MouseViewport;
	CMapArea MapArea;

	CFont *MessageFont;
	int MessageScrollSpeed;

	CUIButton MenuButton;
	CUIButton NetworkMenuButton;
	CUIButton NetworkDiplomacyButton;

	vector<CUIUserButton> UserButtons;

	CMinimap Minimap;
	CStatusLine StatusLine;
	CUITimer Timer;

	Vec2i EditorSettingsAreaTopLeft;
	Vec2i EditorSettingsAreaBottomRight;
	Vec2i EditorButtonAreaTopLeft;
	Vec2i EditorButtonAreaBottomRight;

	void Load();
};

CUserInterface UI

class CIcon

class CIcon
{
	static CIcon *New(const std::string ident);
	static CIcon *Get(const std::string ident);

	tolua_readonly tolua_property__s std::string Ident;
	CPlayerColorGraphic *G;
	int Frame;

	void ClearExtraGraphics();
	void AddSingleSelectionGraphic(CPlayerColorGraphic *g);
	void AddGroupSelectionGraphic(CPlayerColorGraphic *g);
	void AddContainedGraphic(CPlayerColorGraphic *g);
};

ButtonStyle *FindButtonStyle(const std::string style)

bool GetMouseScroll(void)

SetMouseScroll(bool enabled)

bool GetKeyScroll(void)

SetKeyScroll(bool enabled)

bool GetGrabMouse(void)

SetGrabMouse(bool enabled)

bool GetLeaveStops(void)

SetLeaveStops(bool enabled)

int GetDoubleClickDelay(void)

SetDoubleClickDelay(int delay)

int GetHoldClickDelay(void)

SetHoldClickDelay(int delay)

SetScrollMargins(unsigned int top, unsigned int right, unsigned int bottom, unsigned int left)

PixelPos CursorScreenPos

class Color

class Color
{
	Color(int r, int g, int b, int a = 255);
	int r;
	int g;
	int b;
	int a;
};

class Graphics

class Graphics
{
	enum {
		LEFT = 0,
		CENTER,
		RIGHT
	};

class Widget

class Widget
{
	virtual void setWidth(int width);
	virtual int getWidth() const;
	virtual void setHeight(int height);
	virtual int getHeight() const;
	virtual void setSize(int width, int height);
	virtual void setX(int x);
	virtual int getX() const;
	virtual void setY(int y);
	virtual int getY() const;
	virtual void setPosition(int x, int y);
	virtual void setBorderSize(int width);
	virtual unsigned int getBorderSize() const;
	virtual void setEnabled(bool enabled);
	virtual bool isEnabled() const;
	virtual void setVisible(bool visible);
	virtual bool isVisible() const;

	virtual void setDirty(bool isDirty);

	virtual void setBaseColor(const Color color);
	virtual const Color &getBaseColor() const;
	virtual void setForegroundColor(const Color color);
	virtual const Color &getForegroundColor() const;
	virtual void setBackgroundColor(const Color color);
	virtual const Color &getBackgroundColor() const;
	virtual void setDisabledColor(const Color color);
	virtual const Color &getDisabledColor() const;

	static void setGlobalFont(CFont *font);
	virtual void setForegroundColor(const Color color);
	virtual void setBackgroundColor(const Color color);
	virtual void setBaseColor(const Color color);
	virtual void setSize(int width, int height);
	virtual void setBorderSize(int width);
	virtual void setFont(CFont *font);

	virtual int getHotKey() const;
	virtual void setHotKey(const int key);
	virtual void setHotKey(const char *key);

        virtual void requestFocus();

	virtual void addActionListener(LuaActionListener *actionListener);
        virtual void addMouseListener(LuaActionListener *actionListener);
        virtual void addKeyListener(LuaActionListener *actionListener);
};

class BasicContainer : public Widget

class BasicContainer : public Widget
{
};

class ScrollArea : public BasicContainer

class ScrollArea : public BasicContainer
{
	ScrollArea();
	virtual void setContent(Widget *widget);
	virtual Widget *getContent();
	virtual void setScrollbarWidth(int width);
	virtual int getScrollbarWidth();
        virtual void scrollToBottom();
        virtual void scrollToTop();
};

class ImageWidget : public Widget

class ImageWidget : public Widget
{
	ImageWidget(CGraphic *image);
        ImageWidget(Mng *image);
        ImageWidget(Movie *image);
};

class Button : public Widget

class Button : public Widget
{
};

class ButtonWidget : public Button

class ButtonWidget : public Button
{
	ButtonWidget(const std::string caption);
	virtual void setCaption(const std::string caption);
	virtual const std::string &getCaption() const;
	virtual void adjustSize();
};

class ImageButton : public Button

class ImageButton : public Button
{
	ImageButton();
	ImageButton(const std::string caption);

	void setNormalImage(CGraphic *image);
	void setPressedImage(CGraphic *image);
	void setDisabledImage(CGraphic *image);
};

class RadioButton : public Widget

class RadioButton : public Widget
{
	RadioButton();
	RadioButton(const std::string caption, const std::string group, bool marked = false);

	virtual bool isMarked();
	virtual void setMarked(bool marked);
	virtual const std::string &getCaption() const;
	virtual void setCaption(const std::string caption);
	virtual void setGroup(const std::string group);
	virtual const std::string &getGroup() const;
	virtual void adjustSize();
};

class ImageRadioButton : public RadioButton

class ImageRadioButton : public RadioButton
{
	ImageRadioButton();
	ImageRadioButton(const std::string caption, const std::string group, bool marked = false);

	void setUncheckedNormalImage(CGraphic *image);
	void setUncheckedPressedImage(CGraphic *image);
	void setUncheckedDisabledImage(CGraphic *image);
	void setCheckedNormalImage(CGraphic *image);
	void setCheckedPressedImage(CGraphic *image);
	void setCheckedDisabledImage(CGraphic *image);
};

class CheckBox : public Widget

class CheckBox : public Widget
{
	CheckBox();
	CheckBox(const std::string caption, bool marked = false);

	virtual bool isMarked() const;
	virtual void setMarked(bool marked);
	virtual const std::string &getCaption() const;
	virtual void setCaption(const std::string caption);
	virtual void adjustSize();
};

class ImageCheckBox : public CheckBox

class ImageCheckBox : public CheckBox
{
	ImageCheckBox();
	ImageCheckBox(const std::string caption, bool marked = false);

	void setUncheckedNormalImage(CGraphic *image);
	void setUncheckedPressedImage(CGraphic *image);
	void setUncheckedDisabledImage(CGraphic *image);
	void setCheckedNormalImage(CGraphic *image);
	void setCheckedPressedImage(CGraphic *image);
	void setCheckedDisabledImage(CGraphic *image);
};

class Slider : public Widget

class Slider : public Widget
{
	Slider(double scaleEnd = 1.0);
	Slider(double scaleStart, double scaleEnd);
	virtual void setScale(double scaleStart, double scaleEnd);
	virtual double getScaleStart() const;
	virtual void setScaleStart(double scaleStart);
	virtual double getScaleEnd() const;
	virtual void setScaleEnd(double scaleEnd);
	virtual double getValue();
	virtual void setValue(double value);
	virtual void setMarkerLength(int length);
	virtual int getMarkerLength() const;
	virtual void setOrientation(unsigned int orientation);
	virtual unsigned int getOrientation() const;
	virtual void setStepLength(double length);
	virtual double getStepLength() const;

	enum { HORIZONTAL = 0, VERTICAL };
};

class ImageSlider : public Slider

class ImageSlider : public Slider
{
	ImageSlider(double scaleEnd = 1.0);
	ImageSlider(double scaleStart, double scaleEnd);
	void setMarkerImage(CGraphic *image);
	void setBackgroundImage(CGraphic *image);
	void setDisabledBackgroundImage(CGraphic *image);
};

class Label : public Widget

class Label : public Widget
{
	Label(const std::string caption);
	const std::string &getCaption() const;
	void setCaption(const std::string caption);
	virtual void setAlignment(unsigned int alignment);
	virtual unsigned int getAlignment();
	virtual void adjustSize();
};

class MultiLineLabel : public Widget

class MultiLineLabel : public Widget
{
	MultiLineLabel();
	MultiLineLabel(const std::string caption);

	virtual void setCaption(const std::string caption);
	virtual const std::string &getCaption() const;
	virtual void setAlignment(unsigned int alignment);
	virtual unsigned int getAlignment();
	virtual void setVerticalAlignment(unsigned int alignment);
	virtual unsigned int getVerticalAlignment();
	virtual void setLineWidth(int width);
	virtual int getLineWidth();
	virtual void adjustSize();
	virtual void draw(gcn::Graphics *graphics);

	enum {
		LEFT = 0,
		CENTER,
		RIGHT,
		TOP,
		BOTTOM
	};

class TextBox : public Widget

class TextBox : public Widget
{
	TextBox(const std::string text);
        virtual void setEditable(bool editable);
        virtual std::string getText();
};

class TextField : public Widget

class TextField : public Widget
{
	TextField(const std::string text);
	virtual void setText(const std::string text);
	virtual std::string &getText();
	virtual void setPassword(bool flag);
};

class ImageTextField : public Widget

class ImageTextField : public Widget
{
	ImageTextField(const std::string text);
	virtual void setText(const std::string text);
	virtual std::string &getText();
	void setItemImage(CGraphic *image);
	virtual void setPassword(bool flag);
};

class ListBox : public Widget

class ListBox : public Widget
{
};

class ImageListBox : public ListBox

class ImageListBox : public ListBox
{
};

class ListBoxWidget : public ScrollArea

class ListBoxWidget : public ScrollArea
{
	ListBoxWidget(unsigned int width, unsigned int height);
	void setList(lua_State *lua, lua_Object *lo);
	void setSelected (int selected);
	int getSelected();
};

class ImageListBoxWidget : public ListBoxWidget

class ImageListBoxWidget : public ListBoxWidget
{
	ImageListBoxWidget(unsigned int width, unsigned int height);
	void setList(lua_State *lua, lua_Object *lo);
	void setSelected (int selected);
	int getSelected();
	void setItemImage(CGraphic *image);
	void setUpButtonImage(CGraphic *image);
	void setUpPressedButtonImage(CGraphic *image);
	void setDownButtonImage(CGraphic *image);
	void setDownPressedButtonImage(CGraphic *image);
	void setLeftButtonImage(CGraphic *image);
	void setLeftPressedButtonImage(CGraphic *image);
	void setRightButtonImage(CGraphic *image);
	void setRightPressedButtonImage(CGraphic *image);
	void setHBarImage(CGraphic *image);
	void setVBarImage(CGraphic *image);
	void setMarkerImage(CGraphic *image);
};

class Window : public BasicContainer

class Window : public BasicContainer
{
	Window();
	Window(const std::string caption);
	Window(Widget *content, const std::string caption = "");

	virtual void setCaption(const std::string caption);
	virtual const std::string &getCaption() const;
	virtual void setAlignment(unsigned int alignment);
	virtual unsigned int getAlignment() const;
	virtual void setContent(Widget* widget);
	virtual Widget* getContent() const;
	virtual void setPadding(unsigned int padding);
	virtual unsigned int getPadding() const;
	virtual void setTitleBarHeight(unsigned int height);
	virtual unsigned int getTitleBarHeight();
	virtual void setMovable(bool movable);
	virtual bool isMovable() const;
	virtual void resizeToContent();
	virtual void setOpaque(bool opaque);
	virtual bool isOpaque();
};

class Windows : public Window

class Windows : public Window
{
	Windows(const std::string text, int width, int height);
	void add(Widget *widget, int x, int y);
};

class ScrollingWidget : public ScrollArea

class ScrollingWidget : public ScrollArea
{
	ScrollingWidget(int width, int height);
	void add(Widget *widget, int x, int y);
	void restart();
	void setSpeed(float speed);
	float getSpeed();
};

class DropDown : public BasicContainer

class DropDown : public BasicContainer
{
	virtual int getSelected();
	virtual void setSelected(int selected);
	virtual void setScrollArea(ScrollArea* scrollArea);
	virtual ScrollArea *getScrollArea();
	virtual void setListBox(ListBox* listBox);
	virtual ListBox *getListBox();
};

class DropDownWidget : public DropDown

class DropDownWidget : public DropDown
{
	DropDownWidget();
	void setList(lua_State *lua, lua_Object *lo);
	virtual ListBox *getListBox();
	virtual void setSize(int width, int height);
};

class ImageDropDownWidget : public DropDown

class ImageDropDownWidget : public DropDown
{
	ImageDropDownWidget();
	void setList(lua_State *lua, lua_Object *lo);
	virtual ListBox *getListBox();
	virtual void setSize(int width, int height);
	void setItemImage(CGraphic *image);
	void setDownNormalImage(CGraphic *image);
	void setDownPressedImage(CGraphic *image);
};

class StatBoxWidget : public Widget

class StatBoxWidget : public Widget
{
	StatBoxWidget(int width, int height);

	void setCaption(const std::string s);
	const std::string &getCaption() const;
	void setPercent(const int percent);
	int getPercent() const;
};

class Container : public BasicContainer

class Container : public BasicContainer
{
	Container();
	virtual void setOpaque(bool opaque);
	virtual bool isOpaque() const;
	virtual void add(Widget *widget, int x, int y);
	virtual void remove(Widget *widget);
	virtual void clear();
};

class MenuScreen : public Container

class MenuScreen : public Container
{
	MenuScreen();

	int run(bool loop = true);
	void stop(int result = 0);
	void stopAll(int result = 0);
	void addLogicCallback(LuaActionListener *actionListener);
	void setDrawMenusUnder(bool drawunder);
	bool getDrawMenusUnder();
};

CenterOnMessage()

ToggleShowMessages()

SetMaxMessageCount(int max)

UiFindIdleWorker()

CycleViewportMode(int step)

UiToggleTerrain()

UiTrackUnit()

SetNewViewportMode(ViewportModeType new_mode)

SetDefaultTextColors(const std::string &normal, const std::string &reverse)

LoadDecorations()

InitUserInterface()