Enable a*.
@param l Lua state.
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;
}
Parse missile-type.
@param l Lua state.
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;
}
Create a missile.
@param l Lua state.
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;
}
Define burning building missiles.
@param l Lua state.
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;
}
Create a missile on the map
@param l Lua state.
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: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;
}
/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;
}
/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;
}
Define a cursor.
@param l Lua state.
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;
}
Set the current game cursor.
@param l Lua state.
static int CclSetGameCursor(lua_State *l)
{
LuaCheckArgs(l, 1);
GameCursor = CursorByIdent(LuaToString(l, 1));
return 0;
}
Set the video sync speed
@param l Lua state.
static int CclSetVideoSyncSpeed(lua_State *l)
{
LuaCheckArgs(l, 1);
VideoSyncSpeed = LuaToNumber(l, 1);
return 0;
}
Add a trigger.
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;
}
Set the active triggers
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;
}
Return the number of units of a given unit-type and player at a location.
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;
}
Player has the quantity of unit-type near to unit-type.
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 ¢erUnit = *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;
}
Player has the quantity of rescued unit-type near to unit-type.
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 ¢erUnit = *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;
}
Parse log
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;
}
Parse replay-log
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;
}
Return of game name.
@param l Lua state.
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;
}
/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;
}
Set God mode.
@param l Lua state.
@return The old mode.
static int CclSetGodMode(lua_State *l)
{
LuaCheckArgs(l, 1);
GodMode = LuaToBoolean(l, 1);
return 0;
}
Get God mode.
@param l Lua state.
@return God mode.
static int CclGetGodMode(lua_State *l)
{
LuaCheckArgs(l, 0);
lua_pushboolean(l, GodMode);
return 1;
}
Set resource harvesting speed (deprecated).
@param l Lua state.
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;
}
Set resource returning speed (deprecated).
@param l Lua state.
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;
}
Set building speed (deprecated).
@param l Lua state.
static int CclSetSpeedBuild(lua_State *l)
{
LuaCheckArgs(l, 2);
const int player = LuaToNumber(l, 1);
Players[player].SpeedBuild = LuaToNumber(l, 2);
return 0;
}
Get building speed (deprecated).
@param l Lua state.
@return Building speed.
static int CclGetSpeedBuild(lua_State *l)
{
LuaCheckArgs(l, 1);
const int player = LuaToNumber(l, 1);
lua_pushnumber(l, Players[player].SpeedBuild);
return 1;
}
Set training speed (deprecated).
@param l Lua state.
static int CclSetSpeedTrain(lua_State *l)
{
LuaCheckArgs(l, 2);
const int player = LuaToNumber(l, 1);
Players[player].SpeedTrain = LuaToNumber(l, 2);
return 0;
}
Get training speed (deprecated).
@param l Lua state.
@return Training speed.
static int CclGetSpeedTrain(lua_State *l)
{
LuaCheckArgs(l, 1);
const int player = LuaToNumber(l, 1);
lua_pushnumber(l, Players[player].SpeedTrain);
return 1;
}
For debug increase upgrading speed (deprecated).
@param l Lua state.
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;
}
For debug increase researching speed (deprecated).
@param l Lua state.
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;
}
For debug increase all speeds (deprecated).
@param l Lua state.
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;
}
Define default incomes for a new player.
@param l Lua state.
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;
}
Define default action for the resources.
@param l Lua state.
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;
}
Define default names for the resources.
@param l Lua state.
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;
}
Define default names for the resources.
@param l Lua state.
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;
}
Define max amounts for the resources.
@param l Lua state.
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;
}
Affect UseHPForXp.
@param l Lua state.
@return 0.
static int ScriptSetUseHPForXp(lua_State *l)
{
LuaCheckArgs(l, 1);
UseHPForXp = LuaToBoolean(l, 1);
return 0;
}
Set the local player name
@param l Lua state.
static int CclSetLocalPlayerName(lua_State *l)
{
LuaCheckArgs(l, 1);
Parameters::Instance.LocalPlayerName = LuaToString(l, 1);
return 0;
}
Get the local player name
@param l Lua state.
static int CclGetLocalPlayerName(lua_State *l)
{
LuaCheckArgs(l, 0);
lua_pushstring(l, Parameters::Instance.LocalPlayerName.c_str());
return 1;
}
/game/game.cpp:1459 CclSetMenuRace
static int CclSetMenuRace(lua_State *l)
{
LuaCheckArgs(l, 1);
MenuRace = LuaToString(l, 1);
return 0;
}
Get Stratagus Version
static int CclGetStratagusVersion(lua_State *l)
{
LuaCheckArgs(l, 0);
lua_pushstring(l, VERSION);
return 1;
}
Get Stratagus Homepage
static int CclGetStratagusHomepage(lua_State *l)
{
LuaCheckArgs(l, 0);
lua_pushstring(l, HOMEPAGE);
return 1;
}
Load the SavedGameInfo Header
@param l Lua state.
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;
}
Parse the construction.
@param l Lua state.
@note make this more flexible
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;
}
Parse the player configuration.
@param l Lua state.
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;
}
Change unit owner
@param l Lua state.
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;
}
Get ThisPlayer.
@param l Lua state.
static int CclGetThisPlayer(lua_State *l)
{
LuaCheckArgs(l, 0);
if (ThisPlayer) {
lua_pushnumber(l, ThisPlayer - Players);
} else {
lua_pushnumber(l, 0);
}
return 1;
}
Set ThisPlayer.
@param l Lua state.
static int CclSetThisPlayer(lua_State *l)
{
LuaCheckArgs(l, 1);
int plynr = LuaToNumber(l, 1);
ThisPlayer = &Players[plynr];
lua_pushnumber(l, plynr);
return 1;
}
Set MaxSelectable
@param l Lua state.
static int CclSetMaxSelectable(lua_State *l)
{
LuaCheckArgs(l, 1);
MaxSelectable = LuaToNumber(l, 1);
lua_pushnumber(l, MaxSelectable);
return 1;
}
Set player unit limit.
@param l Lua state.
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;
}
Set player unit limit.
@param l Lua state.
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;
}
Set player unit limit.
@param l Lua state.
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;
}
Change the diplomacy from player to another player.
@param l Lua state.
@return FIXME: should return old state.
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;
}
Change the diplomacy from ThisPlayer to another player.
@param l Lua state.
static int CclDiplomacy(lua_State *l)
{
lua_pushnumber(l, ThisPlayer->Index);
lua_insert(l, 1);
return CclSetDiplomacy(l);
}
Change the shared vision from player to another player.
@param l Lua state.
@return FIXME: should return old state.
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;
}
Change the shared vision from ThisPlayer to another player.
@param l Lua state.
static int CclSharedVision(lua_State *l)
{
lua_pushnumber(l, ThisPlayer->Index);
lua_insert(l, 1);
return CclSetSharedVision(l);
}
Change the players revelation type - reveal all units, only buidings or don't reveal anything
@param l Lua state.
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;
}
Define race names
@param l Lua state.
static int CclDefineRaceNames(lua_State *l)
{
PlayerRaces.Clean();
return CclDefineNewRaceNames(l);
}
Define race names
@param l Lua state.
static int CclDefineRaceNames(lua_State *l)
{
PlayerRaces.Clean();
return CclDefineNewRaceNames(l);
}
Define player colors
@param l Lua state.
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;
}
Define player color indexes
@param l Lua state.
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;
}
Make new player colors
@param l Lua state.
static int CclNewPlayerColors(lua_State *l)
{
LuaCheckArgs(l, 0);
SetPlayersPalette();
return 0;
}
Get player data.
@param l Lua state.
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;
}
Set player data.
@param l Lua state.
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;
}
Set ai player algo.
@param l Lua state.
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;
}
Return equivalent lua table for add.
{"Add", {arg1, arg2}}
@param l Lua state.
@return equivalent lua table.
static int CclAdd(lua_State *l)
{
LuaCheckArgs(l, 2);
return Alias(l, "Add");
}
Return equivalent lua table for add.
{"Div", {arg1, arg2}}
@param l Lua state.
@return equivalent lua table.
static int CclSub(lua_State *l)
{
LuaCheckArgs(l, 2);
return Alias(l, "Sub");
}
Return equivalent lua table for add.
{"Mul", {arg1, arg2}}
@param l Lua state.
@return equivalent lua table.
static int CclMul(lua_State *l)
{
LuaCheckArgs(l, 2);
return Alias(l, "Mul");
}
Return equivalent lua table for add.
{"Div", {arg1, arg2}}
@param l Lua state.
@return equivalent lua table.
static int CclDiv(lua_State *l)
{
LuaCheckArgs(l, 2);
return Alias(l, "Div");
}
Return equivalent lua table for add.
{"Min", {arg1, arg2}}
@param l Lua state.
@return equivalent lua table.
static int CclMin(lua_State *l)
{
LuaCheckArgs(l, 2);
return Alias(l, "Min");
}
Return equivalent lua table for add.
{"Max", {arg1, arg2, argn}}
@param l Lua state.
@return equivalent lua table.
static int CclMax(lua_State *l)
{
LuaCheckArgs(l, 2);
return Alias(l, "Max");
}
Return equivalent lua table for add.
{"Rand", {arg1}}
@param l Lua state.
@return equivalent lua table.
static int CclRand(lua_State *l)
{
LuaCheckArgs(l, 1);
return Alias(l, "Rand");
}
Return equivalent lua table for GreaterThan.
{"GreaterThan", {arg1, arg2}}
@param l Lua state.
@return equivalent lua table.
static int CclGreaterThan(lua_State *l)
{
LuaCheckArgs(l, 2);
return Alias(l, "GreaterThan");
}
Return equivalent lua table for LessThan.
{"LessThan", {arg1, arg2}}
@param l Lua state.
@return equivalent lua table.
static int CclLessThan(lua_State *l)
{
LuaCheckArgs(l, 2);
return Alias(l, "LessThan");
}
Return equivalent lua table for Equal.
{"Equal", {arg1, arg2}}
@param l Lua state.
@return equivalent lua table.
static int CclEqual(lua_State *l)
{
LuaCheckArgs(l, 2);
return Alias(l, "Equal");
}
Return equivalent lua table for GreaterThanOrEq.
{"GreaterThanOrEq", {arg1, arg2}}
@param l Lua state.
@return equivalent lua table.
static int CclGreaterThanOrEq(lua_State *l)
{
LuaCheckArgs(l, 2);
return Alias(l, "GreaterThanOrEq");
}
Return equivalent lua table for LessThanOrEq.
{"LessThanOrEq", {arg1, arg2}}
@param l Lua state.
@return equivalent lua table.
static int CclLessThanOrEq(lua_State *l)
{
LuaCheckArgs(l, 2);
return Alias(l, "LessThanOrEq");
}
Return equivalent lua table for NotEqual.
{"NotEqual", {arg1, arg2}}
@param l Lua state.
@return equivalent lua table.
static int CclNotEqual(lua_State *l)
{
LuaCheckArgs(l, 2);
return Alias(l, "NotEqual");
}
Return equivalent lua table for VideoTextLength.
{"VideoTextLength", {Text = arg1, Font = arg2}}
@param l Lua state.
@return equivalent lua table.
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;
}
Return equivalent lua table for StringFind.
{"StringFind", {arg1, arg2}}
@param l Lua state.
@return equivalent lua table.
static int CclStringFind(lua_State *l)
{
LuaCheckArgs(l, 2);
return Alias(l, "StringFind");
}
Return equivalent lua table for .
{"Unit", {Unit = "Attacker", Variable = arg1, Component = "Value" or arg2}}
@param l Lua state.
@return equivalent lua table.
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");
}
Return equivalent lua table for .
{"Unit", {Unit = "Defender", Variable = arg1, Component = "Value" or arg2}}
@param l Lua state.
@return equivalent lua table.
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");
}
Return equivalent lua table for .
{"Unit", {Unit = "Active", Variable = arg1, Component = "Value" or arg2}}
@param l Lua state.
@return equivalent lua table.
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");
}
Return equivalent lua table for .
{"Type", {Type = "Active", Variable = arg1, Component = "Value" or arg2}}
@param l Lua state.
@return equivalent lua table.
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");
}
Return equivalent lua table for Concat.
{"Concat", {arg1}}
@param l Lua state.
@return equivalent lua table.
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");
}
Return equivalent lua table for String.
{"String", {arg1}}
@param l Lua state.
@return equivalent lua table.
static int CclString(lua_State *l)
{
LuaCheckArgs(l, 1);
return Alias(l, "String");
}
Return equivalent lua table for InverseVideo.
{"InverseVideo", {arg1}}
@param l Lua state.
@return equivalent lua table.
static int CclInverseVideo(lua_State *l)
{
LuaCheckArgs(l, 1);
return Alias(l, "InverseVideo");
}
Return equivalent lua table for UnitName.
{"UnitName", {arg1}}
@param l Lua state.
@return equivalent lua table.
static int CclUnitName(lua_State *l)
{
LuaCheckArgs(l, 1);
return Alias(l, "UnitName");
}
Return equivalent lua table for SubString.
{"SubString", {arg1, arg2, arg3}}
@param l Lua state.
@return equivalent lua table.
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");
}
Return equivalent lua table for Line.
{"Line", {arg1, arg2[, arg3]}}
@param l Lua state.
@return equivalent lua table.
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");
}
Return equivalent lua table for Line.
{"Line", "arg1"}
@param l Lua state.
@return equivalent lua table.
static int CclGameInfo(lua_State *l)
{
LuaCheckArgs(l, 1);
return Alias(l, "GameInfo");
}
Return equivalent lua table for PlayerName.
{"PlayerName", {arg1}}
@param l Lua state.
@return equivalent lua table.
static int CclPlayerName(lua_State *l)
{
LuaCheckArgs(l, 1);
return Alias(l, "PlayerName");
}
Return equivalent lua table for PlayerData.
{"PlayerData", {arg1}}
@param l Lua state.
@return equivalent lua table.
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");
}
Return equivalent lua table for If.
{"If", {arg1}}
@param l Lua state.
@return equivalent lua table.
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");
}
Return equivalent lua table for NumIf.
{"NumIf", {arg1}}
@param l Lua state.
@return equivalent lua table.
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");
}
Return the stratagus library path.
@param l Lua state.
@return Current libray path.
static int CclStratagusLibraryPath(lua_State *l)
{
lua_pushstring(l, StratagusLibPath.c_str());
return 1;
}
Return a table with the files or directories found in the subdirectory.
static int CclListDirectory(lua_State *l)
{
return CclFilteredListDirectory(l, 0, 0);
}
Return a table with the files found in the subdirectory.
static int CclListFilesInDirectory(lua_State *l)
{
return CclFilteredListDirectory(l, 0x1, 0x1);
}
Return a table with the files found in the subdirectory.
static int CclListDirsInDirectory(lua_State *l)
{
return CclFilteredListDirectory(l, 0x0, 0x1);
}
Set damage computation method.
@param l Lua state.
static int CclSetDamageFormula(lua_State *l)
{
Assert(l);
if (Damage) {
FreeNumberDesc(Damage);
delete Damage;
}
Damage = CclParseNumberDesc(l);
return 0;
}
Save preferences
@param l Lua state.
static int CclSavePreferences(lua_State *l)
{
LuaCheckArgs(l, 0);
SavePreferences();
return 0;
}
Load a file and execute it.
@param l Lua state.
@return 0 in success, else exit.
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;
}
Load a file into a buffer and return it.
@param l Lua state.
@return buffer or nil on failure
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;
}
Print debug message with info about current script name, line number and function.
@see DebugPrint
@param l Lua state.
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;
}
Define the group.
@param l Lua state.
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;
}
Set the current group id. (Needed for load/save)
@param l Lua state.
static int CclSetGroupId(lua_State *l)
{
int old;
LuaCheckArgs(l, 1);
old = GroupId;
GroupId = LuaToNumber(l, 1);
lua_pushnumber(l, old);
return 1;
}
Define the current selection.
@param l Lua state.
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;
}
Removes Randomization of Player position in Multiplayer mode
@param l Lua state.
static int CclNoRandomPlacementMultiplayer(lua_State *l)
{
LuaCheckArgs(l, 0);
NoRandomPlacementMultiplayer = 1;
return 0;
}
/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;
}
Define helper for AI.
@param l Lua state.
@todo FIXME: the first unit could be a list see ../doc/ccl/ai.html
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;
}
Define helper for AI.
@param l Lua state.
@todo FIXME: the first unit could be a list see ../doc/ccl/ai.html
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;
}
Get the race of the current AI player.
@param l Lua state.
static int CclAiGetRace(lua_State *l)
{
LuaCheckArgs(l, 0);
lua_pushstring(l, PlayerRaces.Name[AiPlayer->Player->Race].c_str());
return 1;
}
Get the number of cycles to sleep.
@param l Lua state
@return Number of return values
static int CclAiGetSleepCycles(lua_State *l)
{
LuaCheckArgs(l, 0);
lua_pushnumber(l, AiSleepCycles);
return 1;
}
Set debugging flag of AI script
@param l Lua state
@return Number of return values
static int CclAiDebug(lua_State *l)
{
LuaCheckArgs(l, 1);
AiPlayer->ScriptDebug = LuaToBoolean(l, 1);
return 0;
}
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
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;
}
Need a unit.
@param l Lua state.
@return Number of return values
static int CclAiNeed(lua_State *l)
{
LuaCheckArgs(l, 1);
InsertUnitTypeRequests(CclGetUnitType(l), 1);
lua_pushboolean(l, 0);
return 1;
}
Set the number of units.
@param l Lua state
@return Number of return values
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;
}
Wait for a unit.
@param l Lua State.
@return Number of return values
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;
}
Get number of active build requests for a unit type.
@param l Lua State.
@return Number of return values
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;
}
Define a force, a groups of units.
@param l Lua state.
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;
}
Release force.
@param l Lua state.
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;
}
Define the role of a force.
@param l Lua state.
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;
}
Check if a force ready.
@param l Lua state.
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;
}
Wait for a force ready.
@param l Lua state.
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;
}
Attack with force.
@param l Lua state.
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;
}
Sleep n cycles.
@param l Lua state.
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;
}
Research an upgrade.
@param l Lua state.
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;
}
Upgrade an unit to an new unit-type.
@param l Lua state.
static int CclAiUpgradeTo(lua_State *l)
{
LuaCheckArgs(l, 1);
CUnitType *type = CclGetUnitType(l);
InsertUpgradeToRequests(type);
lua_pushboolean(l, 0);
return 1;
}
Return the player of the running AI.
@param l Lua state.
@return Player number of the AI.
static int CclAiPlayer(lua_State *l)
{
LuaCheckArgs(l, 0);
lua_pushnumber(l, AiPlayer->Player->Index);
return 1;
}
Set AI player resource reserve.
@param l Lua state.
@return Old resource vector
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;
}
Set AI player resource collect percent.
@param l Lua state.
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;
}
Set AI player build.
@param l Lua state.
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;
}
Dump some AI debug information.
@param l Lua state.
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;
}
Define an AI player.
@param l Lua state.
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;
}
Attack with forces.
@param l Lua state.
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;
}
Wait for a forces ready.
@param l Lua state.
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(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.
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(handle, reward_since_last_call, table_of_state_variables)
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;
}
/ai/script_ai.cpp:1537 CclAiProcessorEnd
static int CclAiProcessorEnd(lua_State *l)
{
CTCPSocket *s = AiProcessorSendState(l, 'E');
s->Close();
delete s;
return 0;
}
Parse a map.
@param l Lua state.
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;
}
Reveal the complete map.
@param l Lua state.
static int CclRevealMap(lua_State *l)
{
LuaCheckArgs(l, 0);
if (CclInConfigFile || !Map.Fields) {
FlagRevealMap = 1;
} else {
Map.Reveal();
}
return 0;
}
Center the map.
@param l Lua state.
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;
}
Define the starting viewpoint for a given player.
@param l Lua state.
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;
}
Show Map Location
@param l Lua state.
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;
}
Define size in pixels (x,y) of a tile in this game
@param l Lua state.
static int CclSetTileSize(lua_State *l)
{
LuaCheckArgs(l, 2);
PixelTileSize.x = LuaToNumber(l, 1);
PixelTileSize.y = LuaToNumber(l, 2);
return 0;
}
Set fog of war on/off.
@param l Lua state.
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;
}
/map/script_map.cpp:229 CclGetFogOfWar
static int CclGetFogOfWar(lua_State *l)
{
LuaCheckArgs(l, 0);
lua_pushboolean(l, !Map.NoFogOfWar);
return 1;
}
Enable display of terrain in minimap.
@param l Lua state.
static int CclSetMinimapTerrain(lua_State *l)
{
LuaCheckArgs(l, 1);
UI.Minimap.WithTerrain = LuaToBoolean(l, 1);
return 0;
}
Define Fog graphics
@param l Lua state.
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;
}
Fog of war opacity.
@param l Lua state.
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;
}
Set Fog color.
@param l Lua state.
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;
}
Set forest regeneration speed.
@param l Lua state.
@return Old speed
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;
}
Load the lua file which will define the tile models
@param l Lua state.
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;
}
Define the type of each player available for the map
@param l Lua state.
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;
}
Define tileset
@param l Lua state.
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;
}
Set the flags like "water" for a tile of a tileset
@param l Lua state.
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;
}
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.
static int CclBuildTilesetTables(lua_State *l)
{
LuaCheckArgs(l, 0);
Map.Tileset->buildTable(l);
return 0;
}
Get the name of the terrain of the tile.
@param l Lua state.
@return The name of the terrain of the tile.
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;
}
Check if the tile's terrain has a particular flag.
@param l Lua state.
@return True if has the flag, false if not.
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;
}
Set the editor's select icon
@param l Lua state.
static int CclSetEditorSelectIcon(lua_State *l)
{
LuaCheckArgs(l, 1);
Editor.Select.Name = LuaToString(l, 1);
return 0;
}
Set the editor's units icon
@param l Lua state.
static int CclSetEditorUnitsIcon(lua_State *l)
{
LuaCheckArgs(l, 1);
Editor.Units.Name = LuaToString(l, 1);
return 0;
}
Set the editor's start location unit
@param l Lua state.
static int CclSetEditorStartUnit(lua_State *l)
{
LuaCheckArgs(l, 1);
Editor.StartUnitName = LuaToString(l, 1);
return 0;
}
Parse Spell.
@param l Lua state.
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;
}
Add a new message.
@param l Lua state.
static int CclAddMessage(lua_State *l)
{
LuaCheckArgs(l, 1);
SetMessage("%s", LuaToString(l, 1));
return 0;
}
Set speed of key scroll
@param l Lua state.
static int CclSetKeyScrollSpeed(lua_State *l)
{
LuaCheckArgs(l, 1);
UI.KeyScrollSpeed = LuaToNumber(l, 1);
return 0;
}
Get speed of key scroll
@param l Lua state.
static int CclGetKeyScrollSpeed(lua_State *l)
{
LuaCheckArgs(l, 0);
lua_pushnumber(l, UI.KeyScrollSpeed);
return 1;
}
Set speed of mouse scroll
@param l Lua state.
static int CclSetMouseScrollSpeed(lua_State *l)
{
LuaCheckArgs(l, 1);
UI.MouseScrollSpeed = LuaToNumber(l, 1);
return 0;
}
Get speed of mouse scroll
@param l Lua state.
static int CclGetMouseScrollSpeed(lua_State *l)
{
LuaCheckArgs(l, 0);
lua_pushnumber(l, UI.MouseScrollSpeed);
return 1;
}
Set speed of middle-mouse scroll
@param l Lua state.
static int CclSetMouseScrollSpeedDefault(lua_State *l)
{
LuaCheckArgs(l, 1);
UI.MouseScrollSpeedDefault = LuaToNumber(l, 1);
return 0;
}
Get speed of middle-mouse scroll
@param l Lua state.
static int CclGetMouseScrollSpeedDefault(lua_State *l)
{
LuaCheckArgs(l, 0);
lua_pushnumber(l, UI.MouseScrollSpeedDefault);
return 0;
}
Set speed of ctrl-middle-mouse scroll
@param l Lua state.
static int CclSetMouseScrollSpeedControl(lua_State *l)
{
LuaCheckArgs(l, 1);
UI.MouseScrollSpeedControl = LuaToNumber(l, 1);
return 0;
}
Get speed of ctrl-middle-mouse scroll
@param l Lua state.
static int CclGetMouseScrollSpeedControl(lua_State *l)
{
LuaCheckArgs(l, 0);
lua_pushnumber(l, UI.MouseScrollSpeedControl);
return 0;
}
Set which missile is used for right click
@param l Lua state.
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;
}
Set which missile shows Damage
@param l Lua state.
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;
}
Set the video resolution.
@param l Lua state.
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;
}
Get the video resolution.
@param l Lua state.
static int CclGetVideoResolution(lua_State *l)
{
LuaCheckArgs(l, 0);
lua_pushnumber(l, Video.Width);
lua_pushnumber(l, Video.Height);
return 2;
}
Set the video fullscreen mode.
@param l Lua state.
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;
}
Get the video fullscreen mode.
@param l Lua state.
static int CclGetVideoFullScreen(lua_State *l)
{
LuaCheckArgs(l, 0);
lua_pushboolean(l, Video.FullScreen);
return 1;
}
Request a specific initial window size
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;
}
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.
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;
}
Default title screens.
@param l Lua state.
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;
}
/ui/script_ui.cpp:300 CclShowTitleScreens
static int CclShowTitleScreens(lua_State *l)
{
LuaCheckArgs(l, 0);
ShowTitleScreens();
lua_pushboolean(l, 1);
return 1;
}
Define the Panels.
Define what is shown in the panel(text, icon, variables)
@param l Lua state.
@return 0.
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;
}
Define the Panels.
Define what is shown in the panel(text, icon, variables)
@param l Lua state.
@return 0.
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;
}
Define the viewports.
@param l Lua state.
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;
}
Fighter right button attacks as default.
@param l Lua state.
static int CclRightButtonAttacks(lua_State *l)
{
LuaCheckArgs(l, 0);
RightButtonAttacks = true;
return 0;
}
Fighter right button moves as default.
@param l Lua state.
static int CclRightButtonMoves(lua_State *l)
{
LuaCheckArgs(l, 0);
RightButtonAttacks = false;
return 0;
}
Enable/disable the fancy buildings.
@param l Lua state.
static int CclSetFancyBuildings(lua_State *l)
{
LuaCheckArgs(l, 1);
FancyBuildings = LuaToBoolean(l, 1);
return 0;
}
Define a button style
@param l Lua state.
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;
}
Clear all buttons
@param l Lua state.
static int CclClearButtons(lua_State *l)
{
LuaCheckArgs(l, 0);
CleanButtons();
return 0;
}
Define a button style
@param l Lua state.
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;
}
Set basic map caracteristics.
@param l Lua state.
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;
}
Define the lua file that will build the map
@param l Lua state.
static int CclDefineMapSetup(lua_State *l)
{
LuaCheckArgs(l, 1);
Map.Info.Filename = LuaToString(l, 1);
return 0;
}
Set selection style.
@param l Lua state.
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;
}
Set the keys which are use for grouping units, helpful for other keyboards
@param l Lua state.
static int CclSetGroupKeys(lua_State *l)
{
LuaCheckArgs(l, 1);
UiGroupKeys = LuaToString(l, 1);
return 0;
}
Set the cut off distance.
@param l Lua state.
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;
}
Glue between c and scheme. Allows to specify some global game sounds
in a ccl file.
@param l Lua state.
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;
}
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
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;
}
Glue between c and scheme. Ask the sound system to associate a
sound id to a sound name.
@param l Lua state.
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;
}
Set the range of a given sound.
@param l Lua state.
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;
}
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
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;
}
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
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;
}
Ask the sound system to play the specified sound.
@param l Lua state.
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;
}
Define a unit-type animation set.
@param l Lua state.
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;
}
Define a new upgrade modifier.
@param l List of modifiers.
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;
}
Define which units/upgrades are allowed.
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;
}
Define which units are allowed and how much.
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;
}
Define the sprite to show variables.
@param l Lua_state
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: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