/pathfinder/script_pathfinder.cpp
AStar


Enable a*.

@param l Lua state.

/pathfinder/script_pathfinder.cpp:101 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 {
			LuaError(l, "Unsupported tag: %s" _C_ value);
		}
	}

	return 0;
}


/missile/script_missile.cpp
DefineMissileType


Parse missile-type.

@param l Lua state.

/missile/script_missile.cpp:234 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:332 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:368 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:417 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

/video/shaders.cpp:396 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

/video/shaders.cpp:365 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

/video/shaders.cpp:386 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/cursor.cpp
DefineCursor


Define a cursor.

@param l Lua state.

/video/cursor.cpp:423 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:435 CclSetGameCursor

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


/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;
}


/game/trigger.cpp
AddTrigger


Add a trigger.

/game/trigger.cpp:464 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:486 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


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

/game/trigger.cpp:196 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);

	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


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

/game/trigger.cpp:258 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


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

/game/trigger.cpp:320 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:573 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 = LuaToUnsignedNumber(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:698 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, "Type")) {
			replay->Type = LuaToNumber(l, -1);
		} else if (!strcmp(value, "Race")) {
			replay->Race = 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->Players[j].Name = LuaToString(l, -1);
					} else if (!strcmp(value, "AIScript")) {
						replay->Players[j].AIScript = LuaToString(l, -1);
					} else if (!strcmp(value, "PlayerColor")) {
						replay->Players[j].PlayerColor = LuaToNumber(l, -1);
					} else if (!strcmp(value, "Race")) {
						replay->Players[j].Race = LuaToNumber(l, -1);
					} else if (!strcmp(value, "Team")) {
						replay->Players[j].Team = LuaToNumber(l, -1);
					} else if (!strcmp(value, "Type")) {
						replay->Players[j].Type = LuaToNumber(l, -1);
					} else {
						LuaError(l, "Unsupported key: %s" _C_ value);
					}
					lua_pop(l, 1);
				}
				lua_pop(l, 1);
			}
		} else if (!strcmp(value, "Resource")) {
			replay->Resource = LuaToNumber(l, -1);
		} else if (!strcmp(value, "NumUnits")) {
			replay->NumUnits = LuaToNumber(l, -1);
		} else if (!strcmp(value, "Difficulty")) {
			replay->Difficulty = LuaToNumber(l, -1);
		} else if (!strcmp(value, "NoFow")) {
			replay->NoFow = LuaToBoolean(l, -1);
		} else if (!strcmp(value, "Inside")) {
			replay->Inside = LuaToBoolean(l, -1);
		} else if (!strcmp(value, "RevealMap")) {
			replay->RevealMap = LuaToNumber(l, -1);
		} else if (!strcmp(value, "GameType")) {
			replay->GameType = LuaToNumber(l, -1);
		} else if (!strcmp(value, "Opponents")) {
			replay->Opponents = LuaToNumber(l, -1);
		} else if (!strcmp(value, "MapRichness")) {
			replay->MapRichness = LuaToNumber(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 {
			LuaError(l, "Unsupported key: %s" _C_ value);
		}
		lua_pop(l, 1);
	}

	CurrentReplay = replay;

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

	return 0;
}


/game/game.cpp
SetGameName


Return of game name.

@param l Lua state.

/game/game.cpp:1125 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:1137 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


Set God mode.

@param l Lua state.

@return The old mode.

/game/game.cpp:1151 CclSetGodMode

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

GetGodMode


Get God mode.

@param l Lua state.

@return God mode.

/game/game.cpp:1165 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:1182 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:1199 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:1212 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:1227 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:1240 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:1255 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:1270 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:1285 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:1306 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:1320 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:1337 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:1354 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:1376 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:1394 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:1408 ScriptSetUseHPForXp

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

SetLocalPlayerName


Set the local player name

@param l Lua state.

/game/game.cpp:1420 CclSetLocalPlayerName

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

GetLocalPlayerName


Get the local player name

@param l Lua state.

/game/game.cpp:1432 CclGetLocalPlayerName

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

SetMenuRace

/game/game.cpp:1459 CclSetMenuRace

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

GetStratagusVersion


Get Stratagus Version

/game/game.cpp:1442 CclGetStratagusVersion

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

GetStratagusHomepage


Get Stratagus Homepage

/game/game.cpp:1452 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:1495 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;
}


/stratagus/construct.cpp
DefineConstruction


Parse the construction.

@param l Lua state.

@note make this more flexible

/stratagus/construct.cpp:285 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


Change unit owner

@param l Lua state.

/stratagus/script_player.cpp:356 CclChangeUnitsOwner

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

	Vec2i pos1;
	Vec2i pos2;
	CclGetPos(l, &pos1.x, &pos1.y, 1);
	CclGetPos(l, &pos2.x, &pos2.y, 2);
	const int oldp = LuaToNumber(l, 3);
	const int newp = LuaToNumber(l, 4);
	std::vector<CUnit *> table;

	Select(pos1, pos2, table, HasSamePlayerAs(Players[oldp]));
	for (size_t i = 0; i != table.size(); ++i) {
		table[i]->ChangeOwner(Players[newp]);
	}
	return 0;
}

GetThisPlayer


Get ThisPlayer.

@param l Lua state.

/stratagus/script_player.cpp:372 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


Set ThisPlayer.

@param l Lua state.

/stratagus/script_player.cpp:387 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


Set MaxSelectable

@param l Lua state.

/stratagus/script_player.cpp:401 CclSetMaxSelectable

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

	lua_pushnumber(l, MaxSelectable);
	return 1;
}

SetAllPlayersUnitLimit


Set player unit limit.

@param l Lua state.

/stratagus/script_player.cpp:417 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


Set player unit limit.

@param l Lua state.

/stratagus/script_player.cpp:433 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


Set player unit limit.

@param l Lua state.

/stratagus/script_player.cpp:449 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


Change the diplomacy from player to another player.

@param l Lua state.

@return FIXME: should return old state.

/stratagus/script_player.cpp:475 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;
}

Diplomacy


Change the diplomacy from ThisPlayer to another player.

@param l Lua state.

/stratagus/script_player.cpp:487 CclDiplomacy

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

SetSharedVision


Change the shared vision from player to another player.

@param l Lua state.

@return FIXME: should return old state.

/stratagus/script_player.cpp:507 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:519 CclSharedVision

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

SetRevelationType


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

@param l Lua state.

/stratagus/script_player.cpp:543 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:592 CclDefineRaceNames

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

DefineNewRaceNames


Define race names

@param l Lua state.

/stratagus/script_player.cpp:592 CclDefineRaceNames

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

DefinePlayerColors


Define player colors

@param l Lua state.

/stratagus/script_player.cpp:626 CclDefinePlayerColors

static int CclDefinePlayerColors(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) {
		PlayerColorNames[i / 2] = 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);
		}
		for (int j = 0; j < numcolors; ++j) {
			lua_rawgeti(l, -1, j + 1);
			PlayerColorsRGB[i / 2][j].Parse(l);
			lua_pop(l, 1);
		}
	}

	return 0;
}

DefinePlayerColorIndex


Define player color indexes

@param l Lua state.

/stratagus/script_player.cpp:659 CclDefinePlayerColorIndex

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

	for (int i = 0; i < PlayerMax; ++i) {
		PlayerColorsRGB[i].clear();
		PlayerColorsRGB[i].resize(PlayerColorIndexCount);
		PlayerColors[i].clear();
		PlayerColors[i].resize(PlayerColorIndexCount, 0);
	}
	return 0;
}

NewColors


Make new player colors

@param l Lua state.

/stratagus/script_player.cpp:639 CclNewPlayerColors

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

	return 0;
}

GetPlayerData


Get player data.

@param l Lua state.

/stratagus/script_player.cpp:816 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


Set player data.

@param l Lua state.

/stratagus/script_player.cpp:924 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


Set ai player algo.

@param l Lua state.

/stratagus/script_player.cpp:945 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/script.cpp
Add


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

@param l Lua state.

@return equivalent lua table.

/stratagus/script.cpp:1557 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:1571 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:1584 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:1597 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:1610 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:1623 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:1636 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:1649 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:1675 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:1701 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:1662 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:1688 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:1714 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:1862 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:1876 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:1463 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:1479 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:1495 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:1511 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:1732 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:1746 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:1759 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.

/stratagus/script.cpp:1772 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:1803 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:1819 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:1833 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:1922 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:1908 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:1787 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:1892 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:1984 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:2046 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:2054 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:2062 CclListDirsInDirectory

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

SetDamageFormula


Set damage computation method.

@param l Lua state.

/stratagus/script.cpp:2078 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:277 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:294 CclLoad

static int CclLoad(lua_State *l)
{
	LuaCheckArgs(l, 1);
	const std::string filename = LibraryFileName(LuaToString(l, 1));
	if (LuaLoadFile(filename) == -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:314 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:2099 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", ar.source, ar.currentline, ar.what, LuaToString(l, 1));
#endif

	return 1;
}


/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/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;
}


/network/netconnect.cpp
NoRandomPlacementMultiplayer


Removes Randomization of Player position in Multiplayer mode

@param l Lua state.

/network/netconnect.cpp:1873 CclNoRandomPlacementMultiplayer

static int CclNoRandomPlacementMultiplayer(lua_State *l)
{
	LuaCheckArgs(l, 0);
	NoRandomPlacementMultiplayer = 1;
	return 0;
}

NetworkDiscoverServers

/network/netconnect.cpp:1893 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;
}


/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:350 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


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:350 CclDefineAi

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;
}

AiGetRace


Get the race of the current AI player.

@param l Lua state.

/ai/script_ai.cpp:503 CclAiGetRace

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

AiGetSleepCycles


Get the number of cycles to sleep.

@param l Lua state

@return Number of return values

/ai/script_ai.cpp:517 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:533 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:581 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


Need a unit.

@param l Lua state.

@return Number of return values

/ai/script_ai.cpp:597 CclAiNeed

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

	lua_pushboolean(l, 0);
	return 1;
}

AiSet


Set the number of units.

@param l Lua state

@return Number of return values

/ai/script_ai.cpp:622 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


Wait for a unit.

@param l Lua State.

@return Number of return values

/ai/script_ai.cpp:678 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:702 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


Define a force, a groups of units.

@param l Lua state.

/ai/script_ai.cpp:780 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:834 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


Define the role of a force.

@param l Lua state.

/ai/script_ai.cpp:807 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:854 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


Wait for a force ready.

@param l Lua state.

/ai/script_ai.cpp:879 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


Attack with force.

@param l Lua state.

/ai/script_ai.cpp:896 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


Sleep n cycles.

@param l Lua state.

/ai/script_ai.cpp:973 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


Research an upgrade.

@param l Lua state.

/ai/script_ai.cpp:995 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


Upgrade an unit to an new unit-type.

@param l Lua state.

/ai/script_ai.cpp:1010 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:1024 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:1048 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


Set AI player resource collect percent.

@param l Lua state.

/ai/script_ai.cpp:1065 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:1080 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


Dump some AI debug information.

@param l Lua state.

/ai/script_ai.cpp:1153 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:1441 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


Attack with forces.

@param l Lua state.

/ai/script_ai.cpp:951 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


Wait for a forces ready.

@param l Lua state.

/ai/script_ai.cpp:923 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:1474 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:1529 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:1537 CclAiProcessorEnd

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


/map/script_map.cpp
StratagusMap


Parse a map.

@param l Lua state.

/map/script_map.cpp:128 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:144 CclRevealMap

static int CclRevealMap(lua_State *l)
{
	LuaCheckArgs(l, 0);
	if (CclInConfigFile || !Map.Fields) {
		FlagRevealMap = 1;
	} else {
		Map.Reveal();
	}
	return 0;
}

CenterMap


Center the map.

@param l Lua state.

/map/script_map.cpp:158 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


Define the starting viewpoint for a given player.

@param l Lua state.

/map/script_map.cpp:174 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:205 CclShowMapLocation

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

	LuaCheckArgs(l, 4);
	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


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

@param l Lua state.

/map/script_map.cpp:342 CclSetTileSize

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

SetFogOfWar


Set fog of war on/off.

@param l Lua state.

/map/script_map.cpp:222 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

/map/script_map.cpp:229 CclGetFogOfWar

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

SetMinimapTerrain


Enable display of terrain in minimap.

@param l Lua state.

/map/script_map.cpp:241 CclSetMinimapTerrain

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

SetFogOfWarGraphics


Define Fog graphics

@param l Lua state.

/map/script_map.cpp:329 CclSetFogOfWarGraphics

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

	LuaCheckArgs(l, 1);
	FogGraphicFile = LuaToString(l, 1);
	if (CMap::FogGraphic) {
		CGraphic::Free(CMap::FogGraphic);
	}
	CMap::FogGraphic = CGraphic::New(FogGraphicFile, PixelTileSize.x, PixelTileSize.y);

	return 0;
}

SetFogOfWarOpacity


Fog of war opacity.

@param l Lua state.

/map/script_map.cpp:263 CclSetFogOfWarOpacity

static int CclSetFogOfWarOpacity(lua_State *l)
{
	LuaCheckArgs(l, 1);
	int i = LuaToNumber(l, 1);
	if (i < 0 || i > 255) {
		PrintFunction();
		fprintf(stdout, "Opacity should be 0 - 256\n");
		i = 100;
	}
	FogOfWarOpacity = i;

	if (!CclInConfigFile) {
		Map.Init();
	}
	return 0;
}

SetFogOfWarColor


Set Fog color.

@param l Lua state.

/map/script_map.cpp:310 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");
	}
	FogOfWarColor.R = r;
	FogOfWarColor.G = g;
	FogOfWarColor.B = b;

	return 0;
}

SetForestRegeneration


Set forest regeneration speed.

@param l Lua state.

@return Old speed

/map/script_map.cpp:286 CclSetForestRegeneration

static int CclSetForestRegeneration(lua_State *l)
{
	LuaCheckArgs(l, 1);
	int i = LuaToNumber(l, 1);
	if (i < 0 || i > 255) {
		PrintFunction();
		fprintf(stdout, "Regeneration speed should be 0 - 255\n");
		i = 100;
	}
	const int old = ForestRegeneration;
	ForestRegeneration = i;

	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:432 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:414 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] = PlayerNeutral;
		} else if (!strcmp(type, "nobody")) {
			Map.Info.PlayerType[i] = PlayerNobody;
		} else if (!strcmp(type, "computer")) {
			Map.Info.PlayerType[i] = PlayerComputer;
		} else if (!strcmp(type, "person")) {
			Map.Info.PlayerType[i] = PlayerPerson;
		} else if (!strcmp(type, "rescue-passive")) {
			Map.Info.PlayerType[i] = PlayerRescuePassive;
		} else if (!strcmp(type, "rescue-active")) {
			Map.Info.PlayerType[i] = PlayerRescueActive;
		} else {
			LuaError(l, "Unsupported tag: %s" _C_ type);
		}
	}
	for (int i = numplayers; i < PlayerMax - 1; ++i) {
		Map.Info.PlayerType[i] = PlayerNobody;
	}
	if (numplayers < PlayerMax) {
		Map.Info.PlayerType[PlayerMax - 1] = PlayerNeutral;
	}
	return 0;
}

DefineTileset


Define tileset

@param l Lua state.

/map/script_map.cpp:450 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:489 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:464 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:512 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:556 CclGetTileTerrainHasFlag

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

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

	unsigned short flag = 0;
	const char *flag_name = LuaToString(l, 3);
	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;
}


/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;
}


/spell/script_spell.cpp
DefineSpell


Parse Spell.

@param l Lua state.

/spell/script_spell.cpp:419 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


Add a new message.

@param l Lua state.

/ui/script_ui.cpp:1154 CclAddMessage

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

SetKeyScrollSpeed


Set speed of key scroll

@param l Lua state.

/ui/script_ui.cpp:81 CclSetKeyScrollSpeed

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

GetKeyScrollSpeed


Get speed of key scroll

@param l Lua state.

/ui/script_ui.cpp:93 CclGetKeyScrollSpeed

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

SetMouseScrollSpeed


Set speed of mouse scroll

@param l Lua state.

/ui/script_ui.cpp:105 CclSetMouseScrollSpeed

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

GetMouseScrollSpeed


Get speed of mouse scroll

@param l Lua state.

/ui/script_ui.cpp:117 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:129 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:141 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:153 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:165 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:183 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:202 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


Set the video resolution.

@param l Lua state.

/ui/script_ui.cpp:220 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


Get the video resolution.

@param l Lua state.

/ui/script_ui.cpp:233 CclGetVideoResolution

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

SetVideoFullScreen


Set the video fullscreen mode.

@param l Lua state.

/ui/script_ui.cpp:250 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


Get the video fullscreen mode.

@param l Lua state.

/ui/script_ui.cpp:262 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:278 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:292 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;
}

SetTitleScreens


Default title screens.

@param l Lua state.

/ui/script_ui.cpp:389 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:300 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:573 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:625 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:659 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:671 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:683 CclRightButtonMoves

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

SetFancyBuildings


Enable/disable the fancy buildings.

@param l Lua state.

/ui/script_ui.cpp:695 CclSetFancyBuildings

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

DefineButton


Define a button style

@param l Lua state.

/ui/script_ui.cpp:859 CclDefineButton

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;
}

ClearButtons


Clear all buttons

@param l Lua state.

/ui/script_ui.cpp:903 CclClearButtons

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

DefineButtonStyle


Define a button style

@param l Lua state.

/ui/script_ui.cpp:859 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


Set basic map caracteristics.

@param l Lua state.

/ui/script_ui.cpp:1184 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


Define the lua file that will build the map

@param l Lua state.

/ui/script_ui.cpp:1197 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:1142 CclSetSelectionStyle

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

	const char *style = LuaToString(l, 1);
	if (!strcmp(style, "rectangle")) {
		DrawSelection = DrawSelectionRectangle;
	} else if (!strcmp(style, "alpha-rectangle")) {
		DrawSelection = DrawSelectionRectangleWithTrans;
	} else if (!strcmp(style, "circle")) {
		DrawSelection = DrawSelectionCircle;
	} else if (!strcmp(style, "alpha-circle")) {
		DrawSelection = DrawSelectionCircleWithTrans;
	} else if (!strcmp(style, "corners")) {
		DrawSelection = DrawSelectionCorners;
	} 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:1166 CclSetGroupKeys

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


/sound/script_sound.cpp
SetGlobalSoundRange


Set the cut off distance.

@param l Lua state.

/sound/script_sound.cpp:326 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:309 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:346 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


Ask the sound system to play the specified sound.

@param l Lua state.

/sound/script_sound.cpp:214 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;
}


/animation/animation.cpp
DefineAnimations


Define a unit-type animation set.

@param l Lua state.

/animation/animation.cpp:747 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;
}


/unit/upgrade.cpp
DefineModifier


Define a new upgrade modifier.

@param l List of modifiers.

/unit/upgrade.cpp:358 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, "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


Define which units/upgrades are allowed.

/unit/upgrade.cpp:421 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:381 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/unit_draw.cpp
DefineSprites


Define the sprite to show variables.

@param l Lua_state

/unit/unit_draw.cpp:327 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

/unit/script_unittype.cpp:1156 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);
	int redefine;
	if (type) {
		redefine = 1;
	} 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, "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 && type->Sprite) {
				CGraphic::Free(type->Sprite);
				type->Sprite = 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) {
				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;
#ifdef USE_MNG
		} else if (!strcmp(value, "Portrait")) {
			if (!lua_istable(l, -1)) {
				LuaError(l, "incorrect argument");
			}
			const int subargs = lua_rawlen(l, -1);
			type->Portrait.Num = subargs;
			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) {
				type->Portrait.Files[k] = LuaToString(l, -1, k + 1);
			}
#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, "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, "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, "DeathExplosion")) {
			type->DeathExplosion = 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