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;
}
Description
Add a new message.
Example:
AddMessage("Hello World!")
static int CclAddMessage(lua_State *l)
{
LuaCheckArgs(l, 1);
SetMessage("%s", LuaToString(l, 1));
return 0;
}
Description
Set speed of key scroll
@param l Lua state.
Example:
SetKeyScrollSpeed(4)
static int CclSetKeyScrollSpeed(lua_State *l)
{
LuaCheckArgs(l, 1);
UI.KeyScrollSpeed = LuaToNumber(l, 1);
return 0;
}
Description
Get speed of key scroll
@param l Lua state.
Example:
scroll_speed = GetKeyScrollSpeed()
print(scroll_speed)
static int CclGetKeyScrollSpeed(lua_State *l)
{
LuaCheckArgs(l, 0);
lua_pushnumber(l, UI.KeyScrollSpeed);
return 1;
}
Description
Set speed of mouse scroll
@param l Lua state.
Example:
SetMouseScrollSpeed(2)
static int CclSetMouseScrollSpeed(lua_State *l)
{
LuaCheckArgs(l, 1);
UI.MouseScrollSpeed = LuaToNumber(l, 1);
return 0;
}
Description
Get speed of mouse scroll
@param l Lua state.
Example:
scroll_speed = GetMouseScrollSpeed()
print(scroll_speed)
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;
}
Description
Set the video resolution.
@param l Lua state.
Example:
SetVideoResolution(640,480)
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;
}
Description
Get the video resolution.
@param l Lua state.
Example:
width,height = GetVideoResolution()
print("Resolution is " .. width .. "x" .. height)
static int CclGetVideoResolution(lua_State *l)
{
LuaCheckArgs(l, 0);
lua_pushnumber(l, Video.Width);
lua_pushnumber(l, Video.Height);
return 2;
}
Description
Set the video fullscreen mode.
@param l Lua state.
Example:
-- Full Screen mode enabled
SetVideoFullScreen(true)
-- Full Screen mode disabled
SetVideoFullScreen(false)
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;
}
Description
Get the video fullscreen mode.
@param l Lua state.
Example:
fullscreenmode = GetVideoFullScreen()
print(fullscreenmode)
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;
}
Description
Declare which codepage the font files are in. Text is handled internally
as UTF-8 everywhere, but the font rendering system uses graphics with 256
symbols. Commonly, DOS and early Windows games used codepage 437 or 1252 for
western European languages, or 866 for Russian and some other cyrillic
writing systems. These are the only ones that are currently supported, but
more can easily be added. All text is mapped into the codepage that is set
for the font files. If the codepage is not one of the supported ones, or if
something doesn't map (for example, some accented characters with codepage
866, or cyrillic letters with codepage 437), a simple "visual" mapping to
7-bit ASCII is used to at least print something that may be recognizable.
static int CclSetFontCodePage(lua_State *l)
{
LuaCheckArgs(l, 1);
FontCodePage = LuaToNumber(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:355 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;
}
Description
Enable/disable the fancy buildings.
@param l Lua state.
Example:
-- Enable fancy buildings
SetFancyBuildings(true)
-- Disable fancy buildings
SetFancyBuildings(false)
static int CclSetFancyBuildings(lua_State *l)
{
LuaCheckArgs(l, 1);
FancyBuildings = LuaToBoolean(l, 1);
return 0;
}
Define a button.
@param l Lua state.
static int CclDefineButton(lua_State *l)
{
LuaCheckArgs(l, 1);
if (!lua_istable(l, 1)) {
LuaError(l, "incorrect argument");
}
ButtonAction ba;
//
// Parse the arguments
//
lua_pushnil(l);
while (lua_next(l, 1)) {
const char *value = LuaToString(l, -2);
if (!strcmp(value, "Pos")) {
ba.Pos = LuaToNumber(l, -1);
} else if (!strcmp(value, "Level")) {
ba.Level = LuaToNumber(l, -1);
} else if (!strcmp(value, "AlwaysShow")) {
ba.AlwaysShow = LuaToBoolean(l, -1);
} else if (!strcmp(value, "Icon")) {
ba.Icon.Name = LuaToString(l, -1);
} else if (!strcmp(value, "Action")) {
value = LuaToString(l, -1);
if (!strcmp(value, "move")) {
ba.Action = ButtonMove;
} else if (!strcmp(value, "stop")) {
ba.Action = ButtonStop;
} else if (!strcmp(value, "attack")) {
ba.Action = ButtonAttack;
} else if (!strcmp(value, "repair")) {
ba.Action = ButtonRepair;
} else if (!strcmp(value, "harvest")) {
ba.Action = ButtonHarvest;
} else if (!strcmp(value, "button")) {
ba.Action = ButtonButton;
} else if (!strcmp(value, "build")) {
ba.Action = ButtonBuild;
} else if (!strcmp(value, "train-unit")) {
ba.Action = ButtonTrain;
} else if (!strcmp(value, "patrol")) {
ba.Action = ButtonPatrol;
} else if (!strcmp(value, "explore")) {
ba.Action = ButtonExplore;
} else if (!strcmp(value, "stand-ground")) {
ba.Action = ButtonStandGround;
} else if (!strcmp(value, "attack-ground")) {
ba.Action = ButtonAttackGround;
} else if (!strcmp(value, "return-goods")) {
ba.Action = ButtonReturn;
} else if (!strcmp(value, "cast-spell")) {
ba.Action = ButtonSpellCast;
} else if (!strcmp(value, "research")) {
ba.Action = ButtonResearch;
} else if (!strcmp(value, "upgrade-to")) {
ba.Action = ButtonUpgradeTo;
} else if (!strcmp(value, "unload")) {
ba.Action = ButtonUnload;
} else if (!strcmp(value, "cancel")) {
ba.Action = ButtonCancel;
} else if (!strcmp(value, "cancel-upgrade")) {
ba.Action = ButtonCancelUpgrade;
} else if (!strcmp(value, "cancel-train-unit")) {
ba.Action = ButtonCancelTrain;
} else if (!strcmp(value, "cancel-build")) {
ba.Action = ButtonCancelBuild;
} else if (!strcmp(value, "callback")) {
ba.Action = ButtonCallbackAction;
} else {
LuaError(l, "Unsupported button action: %s" _C_ value);
}
} else if (!strcmp(value, "Value")) {
if (!lua_isnumber(l, -1) && !lua_isstring(l, -1) && !lua_isfunction(l, -1)) {
LuaError(l, "incorrect argument");
}
if (lua_isfunction(l, -1)) {
ba.Payload = new LuaCallback(l, -1);
} else {
char buf[64];
const char *s2;
if (lua_isnumber(l, -1)) {
snprintf(buf, sizeof(buf), "%ld", (long int)lua_tonumber(l, -1));
s2 = buf;
} else {
s2 = lua_tostring(l, -1);
}
ba.ValueStr = s2;
}
} else if (!strcmp(value, "Allowed")) {
value = LuaToString(l, -1);
if (!strcmp(value, "check-true")) {
ba.Allowed = ButtonCheckTrue;
} else if (!strcmp(value, "check-false")) {
ba.Allowed = ButtonCheckFalse;
} else if (!strcmp(value, "check-upgrade")) {
ba.Allowed = ButtonCheckUpgrade;
} else if (!strcmp(value, "check-individual-upgrade")) {
ba.Allowed = ButtonCheckIndividualUpgrade;
} else if (!strcmp(value, "check-unit-variable")) {
ba.Allowed = ButtonCheckUnitVariable;
} else if (!strcmp(value, "check-units-or")) {
ba.Allowed = ButtonCheckUnitsOr;
} else if (!strcmp(value, "check-units-and")) {
ba.Allowed = ButtonCheckUnitsAnd;
} else if (!strcmp(value, "check-units-not")) {
ba.Allowed = ButtonCheckUnitsNot;
} else if (!strcmp(value, "check-units-nor")) {
ba.Allowed = ButtonCheckUnitsNor;
} else if (!strcmp(value, "check-network")) {
ba.Allowed = ButtonCheckNetwork;
} else if (!strcmp(value, "check-no-network")) {
ba.Allowed = ButtonCheckNoNetwork;
} else if (!strcmp(value, "check-no-work")) {
ba.Allowed = ButtonCheckNoWork;
} else if (!strcmp(value, "check-no-research")) {
ba.Allowed = ButtonCheckNoResearch;
} else if (!strcmp(value, "check-attack")) {
ba.Allowed = ButtonCheckAttack;
} else if (!strcmp(value, "check-upgrade-to")) {
ba.Allowed = ButtonCheckUpgradeTo;
} else if (!strcmp(value, "check-research")) {
ba.Allowed = ButtonCheckResearch;
} else if (!strcmp(value, "check-single-research")) {
ba.Allowed = ButtonCheckSingleResearch;
} else if (!strcmp(value, "check-debug")) {
ba.Allowed = ButtonCheckDebug;
} else {
LuaError(l, "Unsupported action: %s" _C_ value);
}
} else if (!strcmp(value, "AllowArg")) {
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument");
}
std::string allowstr;
const unsigned int subargs = lua_rawlen(l, -1);
for (unsigned int k = 0; k < subargs; ++k) {
const char *s2 = LuaToString(l, -1, k + 1);
allowstr += s2;
if (k != subargs - 1) {
allowstr += ",";
}
}
ba.AllowStr = allowstr;
} else if (!strcmp(value, "Key")) {
std::string key(LuaToString(l, -1));
ba.Key = GetHotKey(key);
} else if (!strcmp(value, "Hint")) {
ba.Hint = LuaToString(l, -1);
} else if (!strcmp(value, "Description")) {
ba.Description = LuaToString(l, -1);
} else if (!strcmp(value, "CommentSound")) {
ba.CommentSound.Name = LuaToString(l, -1);
} else if (!strcmp(value, "ButtonCursor")) {
ba.ButtonCursor = LuaToString(l, -1);
} else if (!strcmp(value, "Popup")) {
ba.Popup = LuaToString(l, -1);
} else if (!strcmp(value, "ForUnit")) {
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument");
}
// FIXME: ba.UnitMask shouldn't be a string
std::string umask = ",";
const unsigned subargs = lua_rawlen(l, -1);
for (unsigned int k = 0; k < subargs; ++k) {
const char *s2 = LuaToString(l, -1, k + 1);
umask += s2;
umask += ",";
}
ba.UnitMask = umask;
if (!strncmp(ba.UnitMask.c_str(), ",*,", 3)) {
ba.UnitMask = "*";
}
} else {
LuaError(l, "Unsupported tag: %s" _C_ value);
}
lua_pop(l, 1);
}
AddButton(ba.Pos, ba.Level, ba.Icon.Name, ba.Action, ba.ValueStr, ba.Payload,
ba.Allowed, ba.AllowStr, ba.Key, ba.Hint, ba.Description, ba.CommentSound.Name,
ba.ButtonCursor, ba.UnitMask, ba.Popup, ba.AlwaysShow);
return 0;
}
Clear all buttons
@param l Lua state.
static int CclClearButtons(lua_State *l)
{
LuaCheckArgs(l, 0);
CleanButtons();
return 0;
}
/ui/script_ui.cpp:1186 CclCopyButtonsForUnitType
static int CclCopyButtonsForUnitType(lua_State *l)
{
LuaCheckArgs(l, 2);
// Slot identifier
const char* fromName = LuaToString(l, 1);
CUnitType *from = UnitTypeByIdent(fromName);
const char* toName = LuaToString(l, 2);
CUnitType *to = UnitTypeByIdent(toName);
if (!to) {
LuaError(l, "Unknown unit-type '%s'\n" _C_ toName);
}
if (!from) {
LuaError(l, "Unknown unit-type '%s'\n" _C_ fromName);
}
for (auto btn : UnitButtonTable) {
if (btn->UnitMask.find(fromName) != std::string::npos) {
btn->UnitMask += toName;
btn->UnitMask += ",";
}
}
return 0;
}
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;
}
Description
Set basic map caracteristics.
@param l Lua state.
Example:
PresentMap("Map description", 1, 128, 128, 17)
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;
}
Description
Define the lua file that will build the map
@param l Lua state.
Example:
-- Load map setup from file
DefineMapSetup("Setup.sms")
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)
{
if (lua_gettop(l) < 1) {
LuaError(l, "incorrect argument");
}
const char *style = LuaToString(l, 1);
if (!strcmp(style, "rectangle")) {
LuaCheckArgs(l, 1);
DrawSelection = DrawSelectionRectangle;
} else if (!strcmp(style, "alpha-rectangle")) {
LuaCheckArgs(l, 1);
DrawSelection = DrawSelectionRectangleWithTrans;
} else if (!strcmp(style, "circle")) {
LuaCheckArgs(l, 1);
DrawSelection = DrawSelectionCircle;
} else if (!strcmp(style, "alpha-circle")) {
LuaCheckArgs(l, 1);
DrawSelection = DrawSelectionCircleWithTrans;
} else if (!strcmp(style, "corners")) {
LuaCheckArgs(l, 1);
DrawSelection = DrawSelectionCorners;
} else if (!strcmp(style, "ellipse")) {
LuaCheckArgs(l, 2);
float factor = LuaToFloat(l, 2);
DrawSelection = DrawSelectionEllipse(factor);
} else {
LuaError(l, "Unsupported selection style");
}
return 0;
}
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;
}
Define a new dependency.
@param l Lua state.
static int CclDefineDependency(lua_State *l)
{
const int args = lua_gettop(l);
const char *target = LuaToString(l, 1);
// All or rules.
int or_flag = 0;
for (int j = 1; j < args; ++j) {
if (!lua_istable(l, j + 1)) {
LuaError(l, "incorrect argument");
}
const int subargs = lua_rawlen(l, j + 1);
for (int k = 0; k < subargs; ++k) {
const char *required = LuaToString(l, j + 1, k + 1);
int count = 1;
if (k + 1 < subargs) {
lua_rawgeti(l, j + 1, k + 2);
if (lua_isnumber(l, -1)) {
count = LuaToNumber(l, -1);
++k;
}
lua_pop(l, 1);
}
AddDependency(target, required, count, or_flag);
or_flag = 0;
}
if (j + 1 < args) {
++j;
const char *value = LuaToString(l, j + 1);
if (strcmp(value, "or")) {
LuaError(l, "not or symbol: %s" _C_ value);
return 0;
}
or_flag = 1;
}
}
return 0;
}
Get the dependency.
@todo not written.
@param l Lua state.
static int CclGetDependency(lua_State *l)
{
DebugPrint("FIXME: write this %p\n" _C_(void *)l);
return 0;
}
Checks if dependencies are met.
@return true if the dependencies are met.
@param l Lua state.
Argument 1: player
Argument 2: object which we want to check the dependencies of
static int CclCheckDependency(lua_State *l)
{
LuaCheckArgs(l, 2);
const char *object = LuaToString(l, 2);
lua_pop(l, 1);
const int plynr = TriggerGetPlayer(l);
if (plynr == -1) {
LuaError(l, "bad player: %i" _C_ plynr);
}
CPlayer &player = Players[plynr];
lua_pushboolean(l, CheckDependByIdent(player, object));
return 1;
}
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, "regeneration-frequency")) {
um->Modifier.Variables[HP_INDEX].IncreaseFrequency = LuaToNumber(l, j + 1, 2);
} else if (!strcmp(key, "cost")) {
if (!lua_istable(l, j + 1) || lua_rawlen(l, j + 1) != 2) {
LuaError(l, "incorrect argument");
}
const char *value = LuaToString(l, j + 1, 1);
const int resId = GetResourceIdByName(l, value);
um->Modifier.Costs[resId] = LuaToNumber(l, j + 1, 2);
} else if (!strcmp(key, "storing")) {
if (!lua_istable(l, j + 1) || lua_rawlen(l, j + 1) != 2) {
LuaError(l, "incorrect argument");
}
const char *value = LuaToString(l, j + 1, 1);
const int resId = GetResourceIdByName(l, value);
um->Modifier.Storing[resId] = LuaToNumber(l, j + 1, 2);
} else if (!strcmp(key, "improve-production")) {
const char *value = LuaToString(l, j + 1, 2);
const int resId = GetResourceIdByName(l, value);
um->Modifier.ImproveIncomes[resId] = LuaToNumber(l, j + 1, 3);
} else if (!strcmp(key, "allow-unit")) {
const char *value = LuaToString(l, j + 1, 2);
if (!strncmp(value, "unit-", 5)) {
um->ChangeUnits[UnitTypeIdByIdent(value)] = LuaToNumber(l, j + 1, 3);
} else {
LuaError(l, "unit expected");
}
} else if (!strcmp(key, "allow")) {
const char *value = LuaToString(l, j + 1, 2);
if (!strncmp(value, "upgrade-", 8)) {
um->ChangeUpgrades[UpgradeIdByIdent(value)] = LuaToNumber(l, j + 1, 3);
} else {
LuaError(l, "upgrade expected");
}
} else if (!strcmp(key, "apply-to")) {
const char *value = LuaToString(l, j + 1, 2);
um->ApplyTo[UnitTypeIdByIdent(value)] = 'X';
} else if (!strcmp(key, "convert-to")) {
const char *value = LuaToString(l, j + 1, 2);
um->ConvertTo = UnitTypeByIdent(value);
} else if (!strcmp(key, "research-speed")) {
um->SpeedResearch = LuaToNumber(l, j + 1, 2);
} else {
int index = UnitTypeVar.VariableNameLookup[key]; // variable index;
if (index != -1) {
if (lua_rawlen(l, j + 1) == 3) {
const char *value = LuaToString(l, j + 1, 3);
if (!strcmp(value, "Percent")) {
um->ModifyPercent[index] = LuaToNumber(l, j + 1, 2);
}
} else {
lua_rawgeti(l, j + 1, 2);
if (lua_istable(l, -1)) {
DefineVariableField(l, um->Modifier.Variables + index, -1);
} else if (lua_isnumber(l, -1)) {
um->Modifier.Variables[index].Enable = 1;
um->Modifier.Variables[index].Value = LuaToNumber(l, -1);
um->Modifier.Variables[index].Max = LuaToNumber(l, -1);
} else {
LuaError(l, "bad argument type for '%s'\n" _C_ key);
}
lua_pop(l, 1);
}
} else {
LuaError(l, "wrong tag: %s" _C_ key);
}
}
}
UpgradeModifiers[NumUpgradeModifiers++] = um;
return 0;
}
Description
Define which units/upgrades are allowed.
Example:
DefineAllow("unit-town-hall","AAAAAAAAAAAAAAAA") -- Available for everybody
DefineAllow("unit-stables","FFFFFFFFFFFFFFFF") -- Not available
DefineAllow("upgrade-sword1","RRRRRRRRRRRRRRRR") -- Upgrade already researched.
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;
}
Description
Set training queue
@param l Lua state.
@return The old state of the training queue
Example:
-- Training queue available. Train multiple units.
SetTrainingQueue(true)
-- Train one unit at a time.
SetTrainingQueue(false)
static int CclSetTrainingQueue(lua_State *l)
{
LuaCheckArgs(l, 1);
EnableTrainingQueue = LuaToBoolean(l, 1);
return 0;
}
Set capture buildings
@param l Lua state.
@return The old state of the flag
Example:
SetBuildingCapture(true)
SetBuildingCapture(false)
static int CclSetBuildingCapture(lua_State *l)
{
LuaCheckArgs(l, 1);
EnableBuildingCapture = LuaToBoolean(l, 1);
return 0;
}
Set reveal attacker
@param l Lua state.
@return The old state of the flag
Example:
SetRevealAttacker(true)
SetRevealAttacker(false)
static int CclSetRevealAttacker(lua_State *l)
{
LuaCheckArgs(l, 1);
RevealAttacker = LuaToBoolean(l, 1);
return 0;
}
Set cost multiplier to RepairCost for buildings additional workers helping (0 = no additional cost)
@param l Lua state.
Example:
-- No cost
ResourcesMultiBuildersMultiplier(0)
-- Each builder helping will cost 1 resource
ResourcesMultiBuildersMultiplier(1)
-- Each builder helping will cost 10 resource
ResourcesMultiBuildersMultiplier(10)
static int CclResourcesMultiBuildersMultiplier(lua_State *l)
{
LuaCheckArgs(l, 1);
ResourcesMultiBuildersMultiplier = LuaToNumber(l, 1);
return 0;
}
Parse unit
@param l Lua state.
@todo Verify that vision table is always correct (transporter)
@todo (PlaceUnit() and host-info).
Example:
footman = CreateUnit("unit-footman", 0, {0, 1})
-- The unit will appear selected
Unit(footman,{"selected"})
-- The unit will be considered destroyed
Unit(footman,{"destroyed"})
-- The unit will be considered removed
Unit(footman,{"removed"})
-- The unit will be considered as a summoned unit
Unit(footman,{"summoned",500})
-- The unit will face on south
Unit(footman,{"direction",0})
-- The unit will be displayed with his 3rd frame
Unit(footman,{"frame", 3})
-- The footman will have a high sight
Unit(footman,{"current-sight-range",9})
-- Change the unit color to be the ones from player 1
Unit(footman,{"rescued-from",1})
static int CclUnit(lua_State *l)
{
const int slot = LuaToNumber(l, 1);
if (!lua_istable(l, 2)) {
LuaError(l, "incorrect argument");
}
CUnit *unit = &UnitManager->GetSlotUnit(slot);
bool hadType = unit->Type != NULL;
CUnitType *type = NULL;
CUnitType *seentype = NULL;
CPlayer *player = NULL;
// Parse the list:
const int args = lua_rawlen(l, 2);
for (int j = 0; j < args; ++j) {
const char *value = LuaToString(l, 2, j + 1);
++j;
if (!strcmp(value, "type")) {
type = UnitTypeByIdent(LuaToString(l, 2, j + 1));
} else if (!strcmp(value, "seen-type")) {
seentype = UnitTypeByIdent(LuaToString(l, 2, j + 1));
} else if (!strcmp(value, "player")) {
player = &Players[LuaToNumber(l, 2, j + 1)];
// During a unit's death animation (when action is "die" but the
// unit still has its original type, i.e. it's still not a corpse)
// the unit is already removed from map and from player's
// unit list (=the unit went through LetUnitDie() which
// calls RemoveUnit() and UnitLost()). Such a unit should not
// be put on player's unit list! However, this state is not
// easily detected from this place. It seems that it is
// characterized by
// unit->CurrentAction()==UnitActionDie so we have to wait
// until we parsed at least Unit::Orders[].
Assert(type);
unit->Init(*type);
unit->Seen.Type = seentype;
unit->Active = 0;
unit->Removed = 0;
Assert(UnitNumber(*unit) == slot);
} else if (!strcmp(value, "current-sight-range")) {
unit->CurrentSightRange = LuaToNumber(l, 2, j + 1);
} else if (!strcmp(value, "refs")) {
unit->Refs = LuaToNumber(l, 2, j + 1);
} else if (!strcmp(value, "host-info")) {
lua_rawgeti(l, 2, j + 1);
if (!lua_istable(l, -1) || lua_rawlen(l, -1) != 4) {
LuaError(l, "incorrect argument");
}
Vec2i pos;
int w;
int h;
pos.x = LuaToNumber(l, -1, 1);
pos.y = LuaToNumber(l, -1, 2);
w = LuaToNumber(l, -1, 3);
h = LuaToNumber(l, -1, 4);
MapSight(*player, *unit, pos, w, h, unit->CurrentSightRange, MapMarkTileSight);
// Detectcloak works in container
if (unit->Type->BoolFlag[DETECTCLOAK_INDEX].value) {
MapSight(*player, *unit, pos, w, h, unit->CurrentSightRange, MapMarkTileDetectCloak);
}
// Radar(Jammer) not.
lua_pop(l, 1);
} else if (!strcmp(value, "tile")) {
lua_rawgeti(l, 2, j + 1);
CclGetPos(l, &unit->tilePos.x , &unit->tilePos.y, -1);
lua_pop(l, 1);
unit->Offset = Map.getIndex(unit->tilePos);
} else if (!strcmp(value, "seen-tile")) {
lua_rawgeti(l, 2, j + 1);
CclGetPos(l, &unit->Seen.tilePos.x , &unit->Seen.tilePos.y, -1);
lua_pop(l, 1);
} else if (!strcmp(value, "stats")) {
unit->Stats = &type->Stats[LuaToNumber(l, 2, j + 1)];
} else if (!strcmp(value, "pixel")) {
lua_rawgeti(l, 2, j + 1);
CclGetPos(l, &unit->IX , &unit->IY, -1);
lua_pop(l, 1);
} else if (!strcmp(value, "seen-pixel")) {
lua_rawgeti(l, 2, j + 1);
CclGetPos(l, &unit->Seen.IX , &unit->Seen.IY, -1);
lua_pop(l, 1);
} else if (!strcmp(value, "frame")) {
unit->Frame = LuaToNumber(l, 2, j + 1);
} else if (!strcmp(value, "seen")) {
unit->Seen.Frame = LuaToNumber(l, 2, j + 1);
} else if (!strcmp(value, "not-seen")) {
unit->Seen.Frame = UnitNotSeen;
--j;
} else if (!strcmp(value, "direction")) {
unit->Direction = LuaToNumber(l, 2, j + 1);
} else if (!strcmp(value, "damage-type")) {
unit->DamagedType = LuaToNumber(l, 2, j + 1);
} else if (!strcmp(value, "attacked")) {
// FIXME : unsigned long should be better handled
unit->Attacked = LuaToNumber(l, 2, j + 1);
} else if (!strcmp(value, "auto-repair")) {
unit->AutoRepair = 1;
--j;
} else if (!strcmp(value, "burning")) {
unit->Burning = 1;
--j;
} else if (!strcmp(value, "destroyed")) {
unit->Destroyed = 1;
--j;
} else if (!strcmp(value, "removed")) {
unit->Removed = 1;
--j;
} else if (!strcmp(value, "selected")) {
unit->Selected = 1;
--j;
} else if (!strcmp(value, "summoned")) {
// FIXME : unsigned long should be better handled
unit->Summoned = LuaToNumber(l, 2, j + 1);
} else if (!strcmp(value, "waiting")) {
unit->Waiting = 1;
--j;
} else if (!strcmp(value, "mine-low")) {
unit->MineLow = 1;
--j;
} else if (!strcmp(value, "rescued-from")) {
unit->RescuedFrom = &Players[LuaToNumber(l, 2, j + 1)];
} else if (!strcmp(value, "seen-by-player")) {
const char *s = LuaToString(l, 2, j + 1);
unit->Seen.ByPlayer = 0;
for (int i = 0; i < PlayerMax && *s; ++i, ++s) {
if (*s == '-' || *s == '_' || *s == ' ') {
unit->Seen.ByPlayer &= ~(1 << i);
} else {
unit->Seen.ByPlayer |= (1 << i);
}
}
} else if (!strcmp(value, "seen-destroyed")) {
const char *s = LuaToString(l, 2, j + 1);
unit->Seen.Destroyed = 0;
for (int i = 0; i < PlayerMax && *s; ++i, ++s) {
if (*s == '-' || *s == '_' || *s == ' ') {
unit->Seen.Destroyed &= ~(1 << i);
} else {
unit->Seen.Destroyed |= (1 << i);
}
}
} else if (!strcmp(value, "constructed")) {
unit->Constructed = 1;
--j;
} else if (!strcmp(value, "seen-constructed")) {
unit->Seen.Constructed = 1;
--j;
} else if (!strcmp(value, "seen-state")) {
unit->Seen.State = LuaToNumber(l, 2, j + 1);
} else if (!strcmp(value, "active")) {
unit->Active = 1;
--j;
} else if (!strcmp(value, "ttl")) {
// FIXME : unsigned long should be better handled
unit->TTL = LuaToNumber(l, 2, j + 1);
} else if (!strcmp(value, "threshold")) {
// FIXME : unsigned long should be better handled
unit->Threshold = LuaToNumber(l, 2, j + 1);
} else if (!strcmp(value, "group-id")) {
unit->GroupId = LuaToNumber(l, 2, j + 1);
} else if (!strcmp(value, "last-group")) {
unit->LastGroup = LuaToNumber(l, 2, j + 1);
} else if (!strcmp(value, "resources-held")) {
unit->ResourcesHeld = LuaToNumber(l, 2, j + 1);
} else if (!strcmp(value, "current-resource")) {
lua_rawgeti(l, 2, j + 1);
lua_pushvalue(l, -1);
unit->CurrentResource = CclGetResourceByName(l);
lua_pop(l, 1);
} else if (!strcmp(value, "pathfinder-input")) {
lua_rawgeti(l, 2, j + 1);
lua_pushvalue(l, -1);
unit->pathFinderData->input.Load(l);
lua_pop(l, 1);
} else if (!strcmp(value, "pathfinder-output")) {
lua_rawgeti(l, 2, j + 1);
lua_pushvalue(l, -1);
unit->pathFinderData->output.Load(l);
lua_pop(l, 1);
} else if (!strcmp(value, "wait")) {
unit->Wait = LuaToNumber(l, 2, j + 1);
} else if (!strcmp(value, "anim-data")) {
lua_rawgeti(l, 2, j + 1);
CAnimations::LoadUnitAnim(l, *unit, -1);
lua_pop(l, 1);
} else if (!strcmp(value, "wait-anim-data")) {
lua_rawgeti(l, 2, j + 1);
CAnimations::LoadWaitUnitAnim(l, *unit, -1);
lua_pop(l, 1);
} else if (!strcmp(value, "blink")) {
unit->Blink = LuaToNumber(l, 2, j + 1);
} else if (!strcmp(value, "moving")) {
unit->Moving = 1;
--j;
} else if (!strcmp(value, "re-cast")) {
unit->ReCast = 1;
--j;
} else if (!strcmp(value, "boarded")) {
unit->Boarded = 1;
--j;
} else if (!strcmp(value, "next-worker")) {
lua_rawgeti(l, 2, j + 1);
lua_pushvalue(l, -1);
unit->NextWorker = CclGetUnitFromRef(l);
lua_pop(l, 1);
} else if (!strcmp(value, "resource-workers")) {
lua_rawgeti(l, 2, j + 1);
lua_pushvalue(l, -1);
unit->Resource.Workers = CclGetUnitFromRef(l);
lua_pop(l, 1);
} else if (!strcmp(value, "resource-assigned")) {
lua_rawgeti(l, 2, j + 1);
lua_pushvalue(l, -1);
unit->Resource.Assigned = LuaToNumber(l, -1);
lua_pop(l, 1);
} else if (!strcmp(value, "resource-active")) {
lua_rawgeti(l, 2, j + 1);
lua_pushvalue(l, -1);
unit->Resource.Active = LuaToNumber(l, -1);
lua_pop(l, 1);
} else if (!strcmp(value, "units-boarded-count")) {
unit->BoardCount = LuaToNumber(l, 2, j + 1);
} else if (!strcmp(value, "units-contained")) {
int subargs;
int k;
lua_rawgeti(l, 2, j + 1);
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument");
}
subargs = lua_rawlen(l, -1);
for (k = 0; k < subargs; ++k) {
lua_rawgeti(l, -1, k + 1);
CUnit *u = CclGetUnitFromRef(l);
lua_pop(l, 1);
u->AddInContainer(*unit);
}
lua_pop(l, 1);
} else if (!strcmp(value, "orders")) {
lua_rawgeti(l, 2, j + 1);
lua_pushvalue(l, -1);
CclParseOrders(l, *unit);
lua_pop(l, 1);
// now we know unit's action so we can assign it to a player
Assert(player != NULL);
unit->AssignToPlayer(*player);
if (unit->CurrentAction() == UnitActionBuilt) {
DebugPrint("HACK: the building is not ready yet\n");
// HACK: the building is not ready yet
unit->Player->UnitTypesCount[type->Slot]--;
if (unit->Active) {
unit->Player->UnitTypesAiActiveCount[type->Slot]--;
}
}
} else if (!strcmp(value, "critical-order")) {
lua_rawgeti(l, 2, j + 1);
lua_pushvalue(l, -1);
CclParseOrder(l, *unit , &unit->CriticalOrder);
lua_pop(l, 1);
} else if (!strcmp(value, "saved-order")) {
lua_rawgeti(l, 2, j + 1);
lua_pushvalue(l, -1);
CclParseOrder(l, *unit, &unit->SavedOrder);
lua_pop(l, 1);
} else if (!strcmp(value, "new-order")) {
lua_rawgeti(l, 2, j + 1);
lua_pushvalue(l, -1);
CclParseOrder(l, *unit, &unit->NewOrder);
lua_pop(l, 1);
} else if (!strcmp(value, "goal")) {
unit->Goal = &UnitManager->GetSlotUnit(LuaToNumber(l, 2, j + 1));
} else if (!strcmp(value, "auto-cast")) {
const char *s = LuaToString(l, 2, j + 1);
Assert(SpellTypeByIdent(s));
if (!unit->AutoCastSpell) {
unit->AutoCastSpell = new char[SpellTypeTable.size()];
memset(unit->AutoCastSpell, 0, SpellTypeTable.size());
}
unit->AutoCastSpell[SpellTypeByIdent(s)->Slot] = 1;
} else if (!strcmp(value, "spell-cooldown")) {
lua_rawgeti(l, 2, j + 1);
if (!lua_istable(l, -1) || lua_rawlen(l, -1) != SpellTypeTable.size()) {
LuaError(l, "incorrect argument");
}
if (!unit->SpellCoolDownTimers) {
unit->SpellCoolDownTimers = new int[SpellTypeTable.size()];
memset(unit->SpellCoolDownTimers, 0, SpellTypeTable.size() * sizeof(int));
}
for (size_t k = 0; k < SpellTypeTable.size(); ++k) {
unit->SpellCoolDownTimers[k] = LuaToNumber(l, -1, k + 1);
}
lua_pop(l, 1);
} else {
const int index = UnitTypeVar.VariableNameLookup[value];// User variables
if (index != -1) { // Valid index
lua_rawgeti(l, 2, j + 1);
DefineVariableField(l, unit->Variable + index, -1);
lua_pop(l, 1);
continue;
}
LuaError(l, "Unit: Unsupported tag: %s" _C_ value);
}
}
// Unit may not have been assigned to a player before now. If not,
// do so now. It is only assigned earlier if we have orders.
// for loading of units from a MAP, and not a savegame, we won't
// have orders for those units. They should appear here as if
// they were just created.
if (!unit->Player) {
Assert(player);
unit->AssignToPlayer(*player);
UpdateForNewUnit(*unit, 0);
}
// Revealers are units that can see while removed
if (unit->Removed && unit->Type->BoolFlag[REVEALER_INDEX].value) {
MapMarkUnitSight(*unit);
}
if (!hadType && unit->Container) {
// this unit was assigned to a container before it had a type, so we
// need to actually add it now, since only with a type do we know the
// BoardSize it takes up in the container
CUnit *host = unit->Container;
unit->Container = NULL;
unit->AddInContainer(*host);
}
return 0;
}
Move a unit on map.
@param l Lua state.
@return Returns the slot number of the made placed.
Example:
-- Create the unit
footman = CreateUnit("unit-footman", 0, {7, 4})
-- Move the unit to position 20 (x) and 10 (y)
MoveUnit(footman,{20,10})
static int CclMoveUnit(lua_State *l)
{
LuaCheckArgs(l, 2);
lua_pushvalue(l, 1);
CUnit *unit = CclGetUnit(l);
lua_pop(l, 1);
Vec2i ipos;
CclGetPos(l, &ipos.x, &ipos.y, 2);
if (!unit->Removed) {
unit->Remove(unit->Container);
}
if (UnitCanBeAt(*unit, ipos)) {
unit->Place(ipos);
} else {
const int heading = SyncRand() % 256;
unit->tilePos = ipos;
DropOutOnSide(*unit, heading, NULL);
}
lua_pushvalue(l, 1);
return 1;
}
Description
Remove unit from the map.
@param l Lua state.
@return Returns 1.
Example:
ogre = CreateUnit("unit-ogre", 0, {24, 89})
AddTrigger(
function() return (GameCycle > 150) end,
function()
RemoveUnit(ogre)
return false end -- end of function
)
static int CclRemoveUnit(lua_State *l)
{
LuaCheckArgs(l, 1);
lua_pushvalue(l, 1);
CUnit *unit = CclGetUnit(l);
lua_pop(l, 1);
if (unit) {
unit->Remove(NULL);
LetUnitDie(*unit);
}
lua_pushvalue(l, 1);
return 1;
}
Description
Create a unit and place it on the map
@param l Lua state.
@return Returns the slot number of the made unit.
Example:
CreateUnit("unit-human-transport", 1, {94, 0})
static int CclCreateUnit(lua_State *l)
{
LuaCheckArgs(l, 3);
lua_pushvalue(l, 1);
CUnitType *unittype = CclGetUnitType(l);
if (unittype == NULL) {
LuaError(l, "Bad unittype");
}
lua_pop(l, 1);
Vec2i ipos;
CclGetPos(l, &ipos.x, &ipos.y, 3);
lua_pushvalue(l, 2);
const int playerno = TriggerGetPlayer(l);
lua_pop(l, 1);
if (playerno == -1) {
printf("CreateUnit: You cannot use \"any\" in create-unit, specify a player\n");
LuaError(l, "bad player");
return 0;
}
if (Players[playerno].Type == PlayerTypes::PlayerNobody) {
printf("CreateUnit: player %d does not exist\n", playerno);
LuaError(l, "bad player");
return 0;
}
CUnit *unit = MakeUnit(*unittype, &Players[playerno]);
if (unit == NULL) {
DebugPrint("Unable to allocate unit");
return 0;
} else {
if (UnitCanBeAt(*unit, ipos)
|| (unit->Type->Building && CanBuildUnitType(NULL, *unit->Type, ipos, 0))) {
unit->Place(ipos);
} else {
const int heading = SyncRand() % 256;
unit->tilePos = ipos;
DropOutOnSide(*unit, heading, NULL);
}
UpdateForNewUnit(*unit, 0);
lua_pushnumber(l, UnitNumber(*unit));
return 1;
}
}
Description
'Upgrade' a unit in place to a unit of different type.
@param l Lua state.
@return Returns success.
Example:
-- Make a peon for player 5
peon = CreateUnit("unit-peon", 5, {58, 9})
-- The peon will be trasformed into a Grunt
TransformUnit(peon,"unit-grunt")
static int CclTransformUnit(lua_State *l)
{
lua_pushvalue(l, 1);
CUnit *targetUnit = CclGetUnit(l);
lua_pop(l, 1);
lua_pushvalue(l, 2);
const CUnitType *unittype = TriggerGetUnitType(l);
lua_pop(l, 1);
if (unittype && targetUnit) {
CommandUpgradeTo(*targetUnit, *(CUnitType*)unittype, 1, true);
}
lua_pushvalue(l, 1);
return 1;
}
Description
Damages unit, additionally using another unit as first's attacker
@param l Lua state.
@return Returns the slot number of the made unit.
Example:
-- Make a grunt for player 5
grunt = CreateUnit("unit-grunt", 5, {58, 8})
-- Damage the grunt with 15 points
DamageUnit(-1,grunt,15)
static int CclDamageUnit(lua_State *l)
{
LuaCheckArgs(l, 3);
const int attacker = LuaToNumber(l, 1);
CUnit *attackerUnit = NULL;
if (attacker != -1) {
attackerUnit = &UnitManager->GetSlotUnit(attacker);
}
lua_pushvalue(l, 2);
CUnit *targetUnit = CclGetUnit(l);
lua_pop(l, 1);
const int damage = LuaToNumber(l, 3);
HitUnit(attackerUnit, *targetUnit, damage);
return 1;
}
Set resources held by a unit
@param l Lua state.
static int CclSetResourcesHeld(lua_State *l)
{
LuaCheckArgs(l, 2);
if (lua_isnil(l, 1)) {
return 0;
}
lua_pushvalue(l, 1);
CUnit *unit = CclGetUnit(l);
lua_pop(l, 1);
const int value = LuaToNumber(l, 2);
unit->ResourcesHeld = value;
unit->Variable[GIVERESOURCE_INDEX].Value = value;
unit->Variable[GIVERESOURCE_INDEX].Max = value;
unit->Variable[GIVERESOURCE_INDEX].Enable = 1;
return 0;
}
Set teleport deastination for teleporter unit
@param l Lua state.
static int CclSetTeleportDestination(lua_State *l)
{
LuaCheckArgs(l, 2);
lua_pushvalue(l, 1);
CUnit *unit = CclGetUnit(l);
lua_pop(l, 1);
if (unit->Type->BoolFlag[TELEPORTER_INDEX].value == false) {
LuaError(l, "Unit not a teleporter");
}
lua_pushvalue(l, 2);
CUnit *dest = CclGetUnit(l);
lua_pop(l, 1);
if (dest->IsAliveOnMap()) {
unit->Goal = dest;
}
return 0;
}
Description
Order a unit
@param l Lua state.
OrderUnit(player, unit-type, start_loc, dest_loc, order)
Example:
-- Move transport from position x=94,y=0 to x=80,y=9
OrderUnit(1,"unit-human-transport",{94,0},{80,9},"move")
static int CclOrderUnit(lua_State *l)
{
LuaCheckArgs(l, 5);
lua_pushvalue(l, 1);
const int plynr = TriggerGetPlayer(l);
lua_pop(l, 1);
lua_pushvalue(l, 2);
const CUnitType *unittype = TriggerGetUnitType(l);
lua_pop(l, 1);
if (!lua_istable(l, 3)) {
LuaError(l, "incorrect argument");
}
Vec2i pos1;
pos1.x = LuaToNumber(l, 3, 1);
pos1.y = LuaToNumber(l, 3, 2);
Vec2i pos2;
if (lua_rawlen(l, 3) == 4) {
pos2.x = LuaToNumber(l, 3, 3);
pos2.y = LuaToNumber(l, 3, 4);
} else {
pos2 = pos1;
}
if (!lua_istable(l, 4)) {
LuaError(l, "incorrect argument");
}
Vec2i dpos1;
Vec2i dpos2;
dpos1.x = LuaToNumber(l, 4, 1);
dpos1.y = LuaToNumber(l, 4, 2);
if (lua_rawlen(l, 4) == 4) {
dpos2.x = LuaToNumber(l, 4, 3);
dpos2.y = LuaToNumber(l, 4, 4);
} else {
dpos2 = dpos1;
}
const char *order = LuaToString(l, 5);
std::vector<CUnit *> table;
Select(pos1, pos2, table);
for (size_t i = 0; i != table.size(); ++i) {
CUnit &unit = *table[i];
if (unittype == ANY_UNIT
|| (unittype == ALL_FOODUNITS && !unit.Type->Building)
|| (unittype == ALL_BUILDINGS && unit.Type->Building)
|| unittype == unit.Type) {
if (plynr == -1 || plynr == unit.Player->Index) {
if (!strcmp(order, "move")) {
CommandMove(unit, (dpos1 + dpos2) / 2, 1);
} else if (!strcmp(order, "stop")) {
CommandStopUnit(unit); //Stop the unit
} else if (!strcmp(order, "stand-ground")) {
CommandStandGround(unit,0); //Stand and flush every order
} else if (!strcmp(order, "attack")) {
CUnit *attack = TargetOnMap(unit, dpos1, dpos2);
CommandAttack(unit, (dpos1 + dpos2) / 2, attack, 1);
} else if (!strcmp(order, "explore")) {
CommandExplore(unit, 1);
} else if (!strcmp(order, "patrol")) {
CommandPatrolUnit(unit, (dpos1 + dpos2) / 2, 1);
} else {
LuaError(l, "Unsupported order: %s" _C_ order);
}
}
}
}
return 0;
}
Description
Kill a unit
@param l Lua state.
@return Returns true if a unit was killed.
Example:
-- Kills an ogre controlled by player 3
KillUnit("unit-ogre", 3)
static int CclKillUnit(lua_State *l)
{
LuaCheckArgs(l, 2);
lua_pushvalue(l, 1);
const CUnitType *unittype = TriggerGetUnitType(l);
lua_pop(l, 1);
const int plynr = TriggerGetPlayer(l);
if (plynr == -1) {
CUnitManager::Iterator it = std::find_if(UnitManager->begin(), UnitManager->end(), HasSameUnitTypeAs(unittype));
if (it != UnitManager->end()) {
LetUnitDie(**it);
lua_pushboolean(l, 1);
return 1;
}
} else {
CPlayer &player = Players[plynr];
std::vector<CUnit *>::iterator it = std::find_if(player.UnitBegin(), player.UnitEnd(), HasSameUnitTypeAs(unittype));
if (it != player.UnitEnd()) {
LetUnitDie(**it);
lua_pushboolean(l, 1);
return 1;
}
}
lua_pushboolean(l, 0);
return 1;
}
Description
Kill a unit at a location
@param l Lua state.
@return Returns the number of units killed.
Example:
-- Kill 8 peasants controlled by player 7 from position {27,1} to {34,5}
KillUnitAt("unit-peasant",7,8,{27,1},{34,5})
static int CclKillUnitAt(lua_State *l)
{
LuaCheckArgs(l, 5);
lua_pushvalue(l, 1);
const CUnitType *unittype = TriggerGetUnitType(l);
lua_pop(l, 1);
lua_pushvalue(l, 2);
int plynr = TriggerGetPlayer(l);
lua_pop(l, 1);
int q = LuaToNumber(l, 3);
if (!lua_istable(l, 4) || !lua_istable(l, 5)) {
LuaError(l, "incorrect argument");
}
Vec2i pos1;
Vec2i pos2;
CclGetPos(l, &pos1.x, &pos1.y, 4);
CclGetPos(l, &pos2.x, &pos2.y, 5);
if (pos1.x > pos2.x) {
std::swap(pos1.x, pos2.x);
}
if (pos1.y > pos2.y) {
std::swap(pos1.y, pos2.y);
}
std::vector<CUnit *> table;
Select(pos1, pos2, table);
int s = 0;
for (std::vector<CUnit *>::iterator it = table.begin(); it != table.end() && s < q; ++it) {
CUnit &unit = **it;
if (unittype == ANY_UNIT
|| (unittype == ALL_FOODUNITS && !unit.Type->Building)
|| (unittype == ALL_BUILDINGS && unit.Type->Building)
|| unittype == unit.Type) {
if ((plynr == -1 || plynr == unit.Player->Index) && unit.IsAlive()) {
LetUnitDie(unit);
++s;
}
}
}
lua_pushnumber(l, s);
return 1;
}
Find the next reachable resource unit that gives resource starting from a worker.
Optional third argument is the range to search.
@param l Lua state.
Example:
peon = CreateUnit("unit-peon", 5, {58, 8})
goldmine = FindNextResource(peon, 0)
static int CclFindNextResource(lua_State *l)
{
const int nargs = lua_gettop(l);
if (nargs < 2 || nargs > 3) {
LuaError(l, "incorrect argument count");
}
lua_pushvalue(l, 1);
CUnit *unit = CclGetUnit(l);
lua_pop(l, 1);
lua_pushvalue(l, 2);
const int resource = CclGetResourceByName(l);
lua_pop(l, 1);
const int range = nargs == 3 ? LuaToNumber(l, 3) : 1000;
CUnit *resourceUnit = UnitFindResource(*unit, *unit, range, resource);
if (resourceUnit) {
lua_pushnumber(l, UnitNumber(*unit));
} else {
lua_pushnil(l);
}
return 1;
}
Description
Get a player's units
@param l Lua state.
@return Array of units.
Example:
-- Get units from player 0
units = GetUnits(0)
for i, id_unit in ipairs(units) do
print(id_unit)
end
static int CclGetUnits(lua_State *l)
{
LuaCheckArgs(l, 1);
const int plynr = TriggerGetPlayer(l);
lua_newtable(l);
if (plynr == -1) {
int i = 0;
for (CUnitManager::Iterator it = UnitManager->begin(); it != UnitManager->end(); ++it, ++i) {
const CUnit &unit = **it;
lua_pushnumber(l, UnitNumber(unit));
lua_rawseti(l, -2, i + 1);
}
} else {
for (int i = 0; i < Players[plynr].GetUnitCount(); ++i) {
lua_pushnumber(l, UnitNumber(Players[plynr].GetUnit(i)));
lua_rawseti(l, -2, i + 1);
}
}
return 1;
}
Description
Get a player's units in rectangle box specified with 2 coordinates
@param l Lua state.
@return Array of units.
Example:
circlePower = CreateUnit("unit-circle-of-power", 15, {59, 4})
-- Get the units near the circle of power.
unitsOnCircle = GetUnitsAroundUnit(circle,1,true)
static int CclGetUnitsAroundUnit(lua_State *l)
{
const int nargs = lua_gettop(l);
if (nargs != 2 && nargs != 3) {
LuaError(l, "incorrect argument\n");
}
const int slot = LuaToNumber(l, 1);
const CUnit &unit = UnitManager->GetSlotUnit(slot);
const int range = LuaToNumber(l, 2);
bool allUnits = false;
if (nargs == 3) {
allUnits = LuaToBoolean(l, 3);
}
lua_newtable(l);
std::vector<CUnit *> table;
if (allUnits) {
SelectAroundUnit(unit, range, table, HasNotSamePlayerAs(Players[PlayerNumNeutral]));
} else {
SelectAroundUnit(unit, range, table, HasSamePlayerAs(*unit.Player));
}
size_t n = 0;
for (size_t i = 0; i < table.size(); ++i) {
if (table[i]->IsAliveOnMap()) {
lua_pushnumber(l, UnitNumber(*table[i]));
lua_rawseti(l, -2, ++n);
}
}
return 1;
}
Get the value of the unit bool-flag.
@param l Lua state.
@return The value of the bool-flag of the unit.
static int CclGetUnitBoolFlag(lua_State *l)
{
LuaCheckArgs(l, 2);
lua_pushvalue(l, 1);
const CUnit *unit = CclGetUnit(l);
lua_pop(l, 1);
const char *const value = LuaToString(l, 2);
int index = UnitTypeVar.BoolFlagNameLookup[value];// User bool flags
if (index == -1) {
LuaError(l, "Bad bool-flag name '%s'\n" _C_ value);
}
lua_pushboolean(l, unit->Type->BoolFlag[index].value);
return 1;
}
Description
Get the value of the unit variable.
@param l Lua state.
@return The value of the variable of the unit.
Example:
-- Make a grunt for player 5
grunt = CreateUnit("unit-grunt", 5, {58, 8})
-- Take the name of the unit
unit_name = GetUnitVariable(grunt,"Name")
-- Take the player number based on the unit
player_type = GetUnitVariable(grunt,"PlayerType")
-- Take the value of the armor
armor_value = GetUnitVariable(grunt,"Armor")
-- Show the message in the game.
AddMessage(unit_name .. " " .. player_type .. " " .. armor_value)
static int CclGetUnitVariable(lua_State *l)
{
const int nargs = lua_gettop(l);
Assert(nargs == 2 || nargs == 3);
lua_pushvalue(l, 1);
CUnit *unit = CclGetUnit(l);
if (unit == NULL) {
return 1;
}
UpdateUnitVariables(*unit);
lua_pop(l, 1);
const char *const value = LuaToString(l, 2);
if (!strcmp(value, "RegenerationRate")) {
lua_pushnumber(l, unit->Variable[HP_INDEX].Increase);
} else if (!strcmp(value, "RegenerationFrequency")) {
lua_pushnumber(l, std::max((int)unit->Variable[HP_INDEX].IncreaseFrequency, 1));
} else if (!strcmp(value, "Ident")) {
lua_pushstring(l, unit->Type->Ident.c_str());
} else if (!strcmp(value, "ResourcesHeld")) {
lua_pushnumber(l, unit->ResourcesHeld);
} else if (!strcmp(value, "GiveResourceType")) {
lua_pushnumber(l, unit->Type->GivesResource);
} else if (!strcmp(value, "CurrentResource")) {
lua_pushnumber(l, unit->CurrentResource);
} else if (!strcmp(value, "Name")) {
lua_pushstring(l, unit->Type->Name.c_str());
} else if (!strcmp(value, "PlayerType")) {
lua_pushstring(l, PlayerTypeNames[static_cast<int>(unit->Player->Type)].c_str());
} else if (!strcmp(value, "TTLPercent")) {
if (unit->Summoned && unit->TTL) {
unsigned long time_lived = GameCycle - unit->Summoned;
Assert(time_lived >= 0);
unsigned long time_to_live = unit->TTL - unit->Summoned;
Assert(time_to_live > 0);
double pcnt = time_lived * 100.0 / time_to_live;
int pcnt_i = (int)round(pcnt);
lua_pushinteger(l, pcnt_i);
} else {
lua_pushinteger(l, -1);
}
} else if (!strcmp(value, "IndividualUpgrade")) {
LuaCheckArgs(l, 3);
std::string upgrade_ident = LuaToString(l, 3);
if (CUpgrade::Get(upgrade_ident)) {
lua_pushboolean(l, unit->IndividualUpgrades[CUpgrade::Get(upgrade_ident)->ID]);
} else {
LuaError(l, "Individual upgrade \"%s\" doesn't exist." _C_ upgrade_ident.c_str());
}
return 1;
} else if (!strcmp(value, "Active")) {
lua_pushboolean(l, unit->Active);
return 1;
} else if (!strcmp(value, "Idle")) {
lua_pushboolean(l, unit->IsIdle());
return 1;
} else if (!strcmp(value, "PixelPos")) {
PixelPos pos = unit->GetMapPixelPosCenter();
lua_newtable(l);
lua_pushnumber(l, pos.x);
lua_setfield(l, -2, "x");
lua_pushnumber(l, pos.y);
lua_setfield(l, -2, "y");
return 1;
} else {
int index = UnitTypeVar.VariableNameLookup[value];// User variables
if (index == -1) {
if (nargs == 2) {
index = UnitTypeVar.BoolFlagNameLookup[value];
if (index != -1) {
lua_pushboolean(l, unit->Type->BoolFlag[index].value);
return 1;
}
}
}
if (index == -1) {
LuaError(l, "Bad variable name '%s'\n" _C_ value);
}
if (nargs == 2) {
lua_pushnumber(l, unit->Variable[index].Value);
} else {
const char *const type = LuaToString(l, 3);
if (!strcmp(type, "Value")) {
lua_pushnumber(l, unit->Variable[index].Value);
} else if (!strcmp(type, "Max")) {
lua_pushnumber(l, unit->Variable[index].Max);
} else if (!strcmp(type, "Increase")) {
lua_pushnumber(l, unit->Variable[index].Increase);
} else if (!strcmp(type, "IncreaseFrequency")) {
lua_pushnumber(l, std::max((int)unit->Variable[index].IncreaseFrequency, 1));
} else if (!strcmp(type, "Enable")) {
lua_pushnumber(l, unit->Variable[index].Enable);
} else {
LuaError(l, "Bad variable type '%s'\n" _C_ type);
}
}
}
return 1;
}
Description
Set the value of the unit variable.
@param l Lua state.
@return The new value of the unit.
Example:
-- Create a blacksmith for player 2
blacksmith = CreateUnit("unit-human-blacksmith", 2, {66, 71})
-- Specify the amount of hit points to assign to the blacksmith
SetUnitVariable(blacksmith,"HitPoints",344)
-- Set the blacksmiths color to the color of player 4
SetUnitVariable(blacksmith,"Color",4)
static int CclSetUnitVariable(lua_State *l)
{
const int nargs = lua_gettop(l);
Assert(nargs >= 3 && nargs <= 5);
lua_pushvalue(l, 1);
CUnit *unit = CclGetUnit(l);
lua_pop(l, 1);
const char *const name = LuaToString(l, 2);
int value = 0;
if (!strcmp(name, "Player")) {
value = LuaToNumber(l, 3);
unit->ChangeOwner(Players[value]);
} else if (!strcmp(name, "Color")) {
if (lua_isstring(l, 3)) {
const char *colorName = LuaToString(l, 3);
for (size_t i = 0; i < PlayerColorNames.size(); i++) {
if (PlayerColorNames[i] == colorName) {
unit->Colors = i;
break;
}
}
} else if (lua_isnil(l, 3)) {
unit->Colors = -1;
} else {
value = LuaToNumber(l, 3);
unit->Colors = value;
}
} else if (!strcmp(name, "TTL")) {
value = LuaToNumber(l, 3);
unit->TTL = GameCycle + value;
} else if (!strcmp(name, "Summoned")) {
value = LuaToNumber(l, 3);
unit->Summoned = value;
} else if (!strcmp(name, "RegenerationRate")) {
value = LuaToNumber(l, 3);
unit->Variable[HP_INDEX].Increase = std::min(unit->Variable[HP_INDEX].Max, value);
} else if (!strcmp(name, "RegenerationFrequency")) {
value = LuaToNumber(l, 3);
unit->Variable[HP_INDEX].IncreaseFrequency = value;
if (unit->Variable[HP_INDEX].IncreaseFrequency != value) {
LuaError(l, "RegenerationFrequency out of range!");
}
} else if (!strcmp(name, "IndividualUpgrade")) {
LuaCheckArgs(l, 4);
std::string upgrade_ident = LuaToString(l, 3);
bool has_upgrade = LuaToBoolean(l, 4);
if (CUpgrade::Get(upgrade_ident)) {
if (has_upgrade && unit->IndividualUpgrades[CUpgrade::Get(upgrade_ident)->ID] == false) {
IndividualUpgradeAcquire(*unit, CUpgrade::Get(upgrade_ident));
} else if (!has_upgrade && unit->IndividualUpgrades[CUpgrade::Get(upgrade_ident)->ID]) {
IndividualUpgradeLost(*unit, CUpgrade::Get(upgrade_ident));
}
} else {
LuaError(l, "Individual upgrade \"%s\" doesn't exist." _C_ upgrade_ident.c_str());
}
} else if (!strcmp(name, "Active")) {
bool ai_active = LuaToBoolean(l, 3);
if (ai_active != unit->Active) {
if (ai_active) {
unit->Player->UnitTypesAiActiveCount[unit->Type->Slot]++;
} else {
unit->Player->UnitTypesAiActiveCount[unit->Type->Slot]--;
if (unit->Player->UnitTypesAiActiveCount[unit->Type->Slot] < 0) { // if unit AI active count is negative, something wrong happened
fprintf(stderr, "Player %d has a negative %s AI active count of %d.\n", unit->Player->Index, unit->Type->Ident.c_str(), unit->Player->UnitTypesAiActiveCount[unit->Type->Slot]);
}
}
}
unit->Active = ai_active;
} else {
const int index = UnitTypeVar.VariableNameLookup[name];// User variables
if (index == -1) {
LuaError(l, "Bad variable name '%s'\n" _C_ name);
}
value = LuaToNumber(l, 3);
bool stats = false;
if (nargs == 5) {
stats = LuaToBoolean(l, 5);
}
if (stats) { // stat variables
const char *const type = LuaToString(l, 4);
if (!strcmp(type, "Value")) {
unit->Stats->Variables[index].Value = std::min(unit->Stats->Variables[index].Max, value);
} else if (!strcmp(type, "Max")) {
unit->Stats->Variables[index].Max = value;
} else if (!strcmp(type, "Increase")) {
unit->Stats->Variables[index].Increase = value;
} else if (!strcmp(type, "IncreaseFrequency")) {
unit->Stats->Variables[index].IncreaseFrequency = value;
if (unit->Stats->Variables[index].IncreaseFrequency != value) {
LuaError(l, "%s.IncreaseFrequency out of range!" _C_ type);
}
} else if (!strcmp(type, "Enable")) {
unit->Stats->Variables[index].Enable = value;
} else {
LuaError(l, "Bad variable type '%s'\n" _C_ type);
}
} else if (nargs == 3) {
unit->Variable[index].Value = std::min(unit->Variable[index].Max, value);
} else {
const char *const type = LuaToString(l, 4);
if (!strcmp(type, "Value")) {
unit->Variable[index].Value = std::min(unit->Variable[index].Max, value);
} else if (!strcmp(type, "Max")) {
unit->Variable[index].Max = value;
} else if (!strcmp(type, "Increase")) {
unit->Variable[index].Increase = value;
} else if (!strcmp(type, "IncreaseFrequency")) {
unit->Variable[index].IncreaseFrequency = value;
if (unit->Variable[index].IncreaseFrequency != value) {
LuaError(l, "%s.IncreaseFrequency out of range!" _C_ type);
}
} else if (!strcmp(type, "Enable")) {
unit->Variable[index].Enable = value;
} else {
LuaError(l, "Bad variable type '%s'\n" _C_ type);
}
}
}
lua_pushnumber(l, value);
return 1;
}
Get the usage of unit slots during load to allocate memory
@param l Lua state.
static int CclSlotUsage(lua_State *l)
{
UnitManager->Load(l);
return 0;
}
Description
Select a single unit
@param l Lua state.
@return 0, meaning the unit is selected.
Example:
-- Make the hero unit Grom Hellscream for player 5
grom = CreateUnit("unit-beast-cry", 5, {58, 8})
-- Select only the unit Grom Hellscream
SelectSingleUnit(grom)
static int CclSelectSingleUnit(lua_State *l)
{
const int nargs = lua_gettop(l);
Assert(nargs == 1);
lua_pushvalue(l, 1);
CUnit *unit = CclGetUnit(l);
lua_pop(l, 1);
SelectSingleUnit(*unit);
SelectionChanged();
return 0;
}
Enable/disable simplified auto targeting
@param l Lua state.
@return 0 for success, 1 for wrong type;
static int CclEnableSimplifiedAutoTargeting(lua_State *l)
{
LuaCheckArgs(l, 1);
const bool isSimplified = LuaToBoolean(l, 1);
if (!IsNetworkGame()) {
GameSettings.SimplifiedAutoTargeting = isSimplified;
} else {
NetworkSendExtendedCommand(ExtendedMessageAutoTargetingDB,
int(isSimplified), 0, 0, 0, 0);
}
return 0;
}
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;
}
Description
Parse unit-type.
@param l Lua state.
Example:
DefineUnitType("unit-silvermoon-archer", { Name = _("Silvermoon Archer"),
Image = {"file", "human/units/elven_archer.png", "size", {72, 72}},
Animations = "animations-archer", Icon = "icon-archer",
Costs = {"time", 70, "gold", 500, "wood", 50},
Speed = 10,
HitPoints = 45,
DrawLevel = 40,
TileSize = {1, 1}, BoxSize = {33, 33},
SightRange = 6, ComputerReactionRange = 7, PersonReactionRange = 6,
BasicDamage = 4, PiercingDamage = 6, Missile = "missile-arrow",
MaxAttackRange = 4,
Priority = 75,
Points = 60,
Demand = 1,
Corpse = "unit-human-dead-body",
Type = "land",
RightMouseAction = "attack",
CanAttack = true,
CanTargetLand = true, CanTargetSea = true, CanTargetAir = true,
LandUnit = true,
organic = true,
SelectableByRectangle = true,
Sounds = {
"selected", "archer-selected",
"acknowledge", "archer-acknowledge",
"ready", "archer-ready",
"help", "basic human voices help 1",
"dead", "basic human voices dead"} } )
static int CclDefineUnitType(lua_State *l)
{
LuaCheckArgs(l, 2);
if (!lua_istable(l, 2)) {
LuaError(l, "incorrect argument");
}
// Slot identifier
const char *str = LuaToString(l, 1);
CUnitType *type = UnitTypeByIdent(str);
constexpr int redefineSprite = 2;
int redefine;
if (type) {
redefine = 1;
DebugPrint("Redefining unit-type '%s'\n" _C_ str);
} else {
type = NewUnitTypeSlot(str);
redefine = 0;
type->NumDirections = 0;
type->Flip = 1;
}
// Parse the list: (still everything could be changed!)
for (lua_pushnil(l); lua_next(l, 2); lua_pop(l, 1)) {
const char *value = LuaToString(l, -2);
if (!strcmp(value, "Name")) {
type->Name = LuaToString(l, -1);
} else if (!strcmp(value, "Image")) {
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument");
}
int subargs = lua_rawlen(l, -1);
for (int k = 0; k < subargs; ++k) {
value = LuaToString(l, -1, k + 1);
++k;
if (!strcmp(value, "file")) {
type->File = LuaToString(l, -1, k + 1);
} else if (!strcmp(value, "alt-file")) {
type->AltFile = LuaToString(l, -1, k + 1);
} else if (!strcmp(value, "size")) {
lua_rawgeti(l, -1, k + 1);
CclGetPos(l, &type->Width, &type->Height);
lua_pop(l, 1);
} else {
LuaError(l, "Unsupported image tag: %s" _C_ value);
}
}
if (redefine) {
if (type->Sprite && type->Sprite->File != type->File) {
redefine |= redefineSprite;
CGraphic::Free(type->Sprite);
type->Sprite = NULL;
}
if (type->AltSprite && type->AltSprite->File != type->AltFile) {
redefine |= redefineSprite;
CGraphic::Free(type->AltSprite);
type->AltSprite = NULL;
}
if (redefine && type->ShadowSprite) {
redefine |= redefineSprite;
CGraphic::Free(type->ShadowSprite);
type->ShadowSprite = NULL;
}
}
if (type->ShadowFile == shadowMarker) {
type->ShadowFile = type->File;
if (type->ShadowWidth == 0 && type->ShadowHeight == 0) {
type->ShadowWidth = type->Width;
type->ShadowHeight = type->Height;
}
}
} else if (!strcmp(value, "Shadow")) {
// default to same spritemap as unit
if (type->File.length() > 0) {
type->ShadowFile = type->File;
type->ShadowWidth = type->Width;
type->ShadowHeight = type->Height;
} else {
type->ShadowFile = shadowMarker;
}
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument");
}
const int subargs = lua_rawlen(l, -1);
for (int k = 0; k < subargs; ++k) {
value = LuaToString(l, -1, k + 1);
++k;
if (!strcmp(value, "file")) {
type->ShadowFile = LuaToString(l, -1, k + 1);
} else if (!strcmp(value, "size")) {
lua_rawgeti(l, -1, k + 1);
CclGetPos(l, &type->ShadowWidth, &type->ShadowHeight);
lua_pop(l, 1);
} else if (!strcmp(value, "offset")) {
lua_rawgeti(l, -1, k + 1);
CclGetPos(l, &type->ShadowOffsetX, &type->ShadowOffsetY);
lua_pop(l, 1);
} else if (!strcmp(value, "sprite-frame")) {
type->ShadowSpriteFrame = LuaToNumber(l, -1, k + 1);
} else if (!strcmp(value, "scale")) {
type->ShadowScale = LuaToNumber(l, -1, k + 1);
} else {
LuaError(l, "Unsupported shadow tag: %s" _C_ value);
}
}
if (redefine && type->ShadowSprite) {
redefine |= redefineSprite;
CGraphic::Free(type->ShadowSprite);
type->ShadowSprite = NULL;
}
} else if (!strcmp(value, "Offset")) {
CclGetPos(l, &type->OffsetX, &type->OffsetY);
} else if (!strcmp(value, "Flip")) {
type->Flip = LuaToBoolean(l, -1);
} else if (!strcmp(value, "Animations")) {
type->Animations = AnimationsByIdent(LuaToString(l, -1));
if (!type->Animations) {
DebugPrint("Warning animation '%s' not found\n" _C_ LuaToString(l, -1));
}
} else if (!strcmp(value, "Icon")) {
type->Icon.Name = LuaToString(l, -1);
type->Icon.Icon = NULL;
} else if (!strcmp(value, "Portrait")) {
#ifdef USE_MNG
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument");
}
const int subargs = lua_rawlen(l, -1);
int number = 0;
for (int k = 0; k < subargs; ++k) {
const char *s = LuaToString(l, -1, k + 1);
if (strcmp("talking", s)) {
number++;
}
}
type->Portrait.Num = number;
type->Portrait.Talking = 0;
type->Portrait.Files = new std::string[type->Portrait.Num];
type->Portrait.Mngs = new Mng *[type->Portrait.Num];
memset(type->Portrait.Mngs, 0, type->Portrait.Num * sizeof(Mng *));
for (int k = 0; k < subargs; ++k) {
const char *s = LuaToString(l, -1, k + 1);
if (!strcmp("talking", s)) {
type->Portrait.Talking = k;
} else {
type->Portrait.Files[k - (type->Portrait.Talking ? 1 : 0)] = s;
}
}
#endif
} else if (!strcmp(value, "Costs")) {
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument");
}
const int subargs = lua_rawlen(l, -1);
for (int k = 0; k < subargs; ++k) {
lua_rawgeti(l, -1, k + 1);
const int res = CclGetResourceByName(l);
lua_pop(l, 1);
++k;
type->DefaultStat.Costs[res] = LuaToNumber(l, -1, k + 1);
}
} else if (!strcmp(value, "Storing")) {
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument");
}
const int subargs = lua_rawlen(l, -1);
for (int k = 0; k < subargs; ++k) {
lua_rawgeti(l, -1, k + 1);
const int res = CclGetResourceByName(l);
lua_pop(l, 1);
++k;
type->DefaultStat.Storing[res] = LuaToNumber(l, -1, k + 1);
}
} else if (!strcmp(value, "ImproveProduction")) {
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument");
}
const int subargs = lua_rawlen(l, -1);
for (int k = 0; k < subargs; ++k) {
lua_rawgeti(l, -1, k + 1);
const int res = CclGetResourceByName(l);
lua_pop(l, 1);
++k;
type->DefaultStat.ImproveIncomes[res] = DefaultIncomes[res] + LuaToNumber(l, -1, k + 1);
}
} else if (!strcmp(value, "Construction")) {
// FIXME: What if constructions aren't yet loaded?
type->Construction = ConstructionByIdent(LuaToString(l, -1));
} else if (!strcmp(value, "DrawLevel")) {
type->DrawLevel = LuaToNumber(l, -1);
} else if (!strcmp(value, "MaxOnBoard")) {
type->MaxOnBoard = LuaToNumber(l, -1);
} else if (!strcmp(value, "BoardSize")) {
type->BoardSize = LuaToNumber(l, -1);
} else if (!strcmp(value, "ButtonLevelForTransporter")) {
type->ButtonLevelForTransporter = LuaToNumber(l, -1);
} else if (!strcmp(value, "StartingResources")) {
type->StartingResources = LuaToNumber(l, -1);
} else if (!strcmp(value, "RegenerationRate")) {
type->DefaultStat.Variables[HP_INDEX].Increase = LuaToNumber(l, -1);
} else if (!strcmp(value, "RegenerationFrequency")) {
int value = LuaToNumber(l, -1);
type->DefaultStat.Variables[HP_INDEX].IncreaseFrequency = value;
if (type->DefaultStat.Variables[HP_INDEX].IncreaseFrequency != value) {
LuaError(l, "RegenerationFrequency out of range!");
}
} else if (!strcmp(value, "BurnPercent")) {
type->BurnPercent = LuaToNumber(l, -1);
} else if (!strcmp(value, "BurnDamageRate")) {
type->BurnDamageRate = LuaToNumber(l, -1);
} else if (!strcmp(value, "PoisonDrain")) {
type->PoisonDrain = LuaToNumber(l, -1);
} else if (!strcmp(value, "ShieldPoints")) {
if (lua_istable(l, -1)) {
DefineVariableField(l, type->DefaultStat.Variables + SHIELD_INDEX, -1);
} else if (lua_isnumber(l, -1)) {
type->DefaultStat.Variables[SHIELD_INDEX].Max = LuaToNumber(l, -1);
type->DefaultStat.Variables[SHIELD_INDEX].Value = 0;
type->DefaultStat.Variables[SHIELD_INDEX].Increase = 1;
type->DefaultStat.Variables[SHIELD_INDEX].Enable = 1;
}
} else if (!strcmp(value, "TileSize")) {
CclGetPos(l, &type->TileWidth, &type->TileHeight);
} else if (!strcmp(value, "NeutralMinimapColor")) {
type->NeutralMinimapColorRGB.Parse(l);
} else if (!strcmp(value, "Neutral")) {
type->Neutral = LuaToBoolean(l, -1);
} else if (!strcmp(value, "BoxSize")) {
CclGetPos(l, &type->BoxWidth, &type->BoxHeight);
} else if (!strcmp(value, "BoxOffset")) {
CclGetPos(l, &type->BoxOffsetX, &type->BoxOffsetY);
} else if (!strcmp(value, "NumDirections")) {
type->NumDirections = LuaToNumber(l, -1);
} else if (!strcmp(value, "ComputerReactionRange")) {
type->ReactRangeComputer = LuaToNumber(l, -1);
} else if (!strcmp(value, "PersonReactionRange")) {
type->ReactRangePerson = LuaToNumber(l, -1);
} else if (!strcmp(value, "Missile")) {
type->Missile.Name = LuaToString(l, -1);
type->Missile.Missile = NULL;
} else if (!strcmp(value, "MinAttackRange")) {
type->MinAttackRange = LuaToNumber(l, -1);
} else if (!strcmp(value, "MaxAttackRange")) {
type->DefaultStat.Variables[ATTACKRANGE_INDEX].Value = LuaToNumber(l, -1);
type->DefaultStat.Variables[ATTACKRANGE_INDEX].Max = LuaToNumber(l, -1);
type->DefaultStat.Variables[ATTACKRANGE_INDEX].Enable = 1;
} else if (!strcmp(value, "MaxHarvesters")) {
type->DefaultStat.Variables[MAXHARVESTERS_INDEX].Value = LuaToNumber(l, -1);
type->DefaultStat.Variables[MAXHARVESTERS_INDEX].Max = LuaToNumber(l, -1);
} else if (!strcmp(value, "Priority")) {
type->DefaultStat.Variables[PRIORITY_INDEX].Value = LuaToNumber(l, -1);
type->DefaultStat.Variables[PRIORITY_INDEX].Max = LuaToNumber(l, -1);
} else if (!strcmp(value, "AnnoyComputerFactor")) {
type->AnnoyComputerFactor = LuaToNumber(l, -1);
} else if (!strcmp(value, "AiAdjacentRange")) {
type->AiAdjacentRange = LuaToNumber(l, -1);
} else if (!strcmp(value, "DecayRate")) {
type->DecayRate = LuaToNumber(l, -1);
} else if (!strcmp(value, "Corpse")) {
type->CorpseName = LuaToString(l, -1);
type->CorpseType = NULL;
} else if (!strcmp(value, "DamageType")) {
value = LuaToString(l, -1);
//int check = ExtraDeathIndex(value);
type->DamageType = value;
} else if (!strcmp(value, "ExplodeWhenKilled")) {
type->ExplodeWhenKilled = 1;
type->Explosion.Name = LuaToString(l, -1);
type->Explosion.Missile = NULL;
} else if (!strcmp(value, "TeleportCost")) {
type->TeleportCost = LuaToNumber(l, -1);
} else if (!strcmp(value, "TeleportEffectIn")) {
type->TeleportEffectIn = new LuaCallback(l, -1);
} else if (!strcmp(value, "TeleportEffectOut")) {
type->TeleportEffectOut = new LuaCallback(l, -1);
} else if (!strcmp(value, "OnDeath")) {
type->OnDeath = new LuaCallback(l, -1);
} else if (!strcmp(value, "OnHit")) {
type->OnHit = new LuaCallback(l, -1);
} else if (!strcmp(value, "OnEachCycle")) {
type->OnEachCycle = new LuaCallback(l, -1);
} else if (!strcmp(value, "OnEachSecond")) {
type->OnEachSecond = new LuaCallback(l, -1);
} else if (!strcmp(value, "OnInit")) {
type->OnInit = new LuaCallback(l, -1);
} else if (!strcmp(value, "OnReady")) {
type->OnReady = new LuaCallback(l, -1);
} else if (!strcmp(value, "Type")) {
value = LuaToString(l, -1);
if (!strcmp(value, "land")) {
type->UnitType = UnitTypeLand;
} else if (!strcmp(value, "fly")) {
type->UnitType = UnitTypeFly;
} else if (!strcmp(value, "naval")) {
type->UnitType = UnitTypeNaval;
} else {
LuaError(l, "Unsupported Type: %s" _C_ value);
}
} else if (!strcmp(value, "MissileOffsets")) {
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument");
}
const int subargs = lua_rawlen(l, -1);
for (int k = 0; k < subargs; ++k) {
lua_rawgeti(l, -1, k + 1);
if (!lua_istable(l, -1) || lua_rawlen(l, -1) != UnitSides) {
LuaError(l, "incorrect argument");
}
for (int m = 0; m < UnitSides; ++m) {
lua_rawgeti(l, -1, m + 1);
CclGetPos(l, &type->MissileOffsets[m][k].x, &type->MissileOffsets[m][k].y);
lua_pop(l, 1);
}
lua_pop(l, 1);
}
} else if (!strcmp(value, "Impact")) {
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument");
}
const int subargs = lua_rawlen(l, -1);
for (int k = 0; k < subargs; ++k) {
const char *dtype = LuaToString(l, -1, k + 1);
++k;
if (!strcmp(dtype, "general")) {
type->Impact[ANIMATIONS_DEATHTYPES].Name = LuaToString(l, -1, k + 1);
type->Impact[ANIMATIONS_DEATHTYPES].Missile = NULL;
} else if (!strcmp(dtype, "shield")) {
type->Impact[ANIMATIONS_DEATHTYPES + 1].Name = LuaToString(l, -1, k + 1);
type->Impact[ANIMATIONS_DEATHTYPES + 1].Missile = NULL;
} else {
int num = 0;
for (; num < ANIMATIONS_DEATHTYPES; ++num) {
if (dtype == ExtraDeathTypes[num]) {
break;
}
}
if (num == ANIMATIONS_DEATHTYPES) {
LuaError(l, "Death type not found: %s" _C_ dtype);
} else {
type->Impact[num].Name = LuaToString(l, -1, k + 1);
type->Impact[num].Missile = NULL;
}
}
}
} else if (!strcmp(value, "RightMouseAction")) {
value = LuaToString(l, -1);
if (!strcmp(value, "none")) {
type->MouseAction = MouseActionNone;
} else if (!strcmp(value, "attack")) {
type->MouseAction = MouseActionAttack;
} else if (!strcmp(value, "move")) {
type->MouseAction = MouseActionMove;
} else if (!strcmp(value, "harvest")) {
type->MouseAction = MouseActionHarvest;
} else if (!strcmp(value, "spell-cast")) {
type->MouseAction = MouseActionSpellCast;
} else if (!strcmp(value, "sail")) {
type->MouseAction = MouseActionSail;
} else {
LuaError(l, "Unsupported RightMouseAction: %s" _C_ value);
}
} else if (!strcmp(value, "CanAttack")) {
type->CanAttack = LuaToBoolean(l, -1);
} else if (!strcmp(value, "RepairRange")) {
type->RepairRange = LuaToNumber(l, -1);
} else if (!strcmp(value, "RepairHp")) {
type->RepairHP = LuaToNumber(l, -1);
} else if (!strcmp(value, "RepairCosts")) {
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument");
}
const int subargs = lua_rawlen(l, -1);
for (int k = 0; k < subargs; ++k) {
lua_rawgeti(l, -1, k + 1);
const int res = CclGetResourceByName(l);
lua_pop(l, 1);
++k;
type->RepairCosts[res] = LuaToNumber(l, -1, k + 1);
}
} else if (!strcmp(value, "CanTargetLand")) {
if (LuaToBoolean(l, -1)) {
type->CanTarget |= CanTargetLand;
} else {
type->CanTarget &= ~CanTargetLand;
}
} else if (!strcmp(value, "CanTargetSea")) {
if (LuaToBoolean(l, -1)) {
type->CanTarget |= CanTargetSea;
} else {
type->CanTarget &= ~CanTargetSea;
}
} else if (!strcmp(value, "CanTargetAir")) {
if (LuaToBoolean(l, -1)) {
type->CanTarget |= CanTargetAir;
} else {
type->CanTarget &= ~CanTargetAir;
}
} else if (!strcmp(value, "Building")) {
type->Building = LuaToBoolean(l, -1);
} else if (!strcmp(value, "BuildingRules")) {
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument");
}
const int subargs = lua_rawlen(l, -1);
// Free any old restrictions if they are redefined
for (std::vector<CBuildRestriction *>::iterator b = type->BuildingRules.begin();
b != type->BuildingRules.end(); ++b) {
delete *b;
}
type->BuildingRules.clear();
for (int k = 0; k < subargs; ++k) {
lua_rawgeti(l, -1, k + 1);
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument");
}
ParseBuildingRules(l, type->BuildingRules);
lua_pop(l, 1);
}
} else if (!strcmp(value, "AiBuildingRules")) {
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument");
}
const int subargs = lua_rawlen(l, -1);
// Free any old restrictions if they are redefined
for (std::vector<CBuildRestriction *>::iterator b = type->AiBuildingRules.begin();
b != type->AiBuildingRules.end(); ++b) {
delete *b;
}
type->AiBuildingRules.clear();
for (int k = 0; k < subargs; ++k) {
lua_rawgeti(l, -1, k + 1);
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument");
}
ParseBuildingRules(l, type->AiBuildingRules);
lua_pop(l, 1);
}
} else if (!strcmp(value, "AutoBuildRate")) {
type->AutoBuildRate = LuaToNumber(l, -1);
} else if (!strcmp(value, "LandUnit")) {
type->LandUnit = LuaToBoolean(l, -1);
} else if (!strcmp(value, "AirUnit")) {
type->AirUnit = LuaToBoolean(l, -1);
} else if (!strcmp(value, "SeaUnit")) {
type->SeaUnit = LuaToBoolean(l, -1);
} else if (!strcmp(value, "RandomMovementProbability")) {
type->RandomMovementProbability = LuaToNumber(l, -1);
} else if (!strcmp(value, "RandomMovementDistance")) {
type->RandomMovementDistance = LuaToNumber(l, -1);
} else if (!strcmp(value, "ClicksToExplode")) {
type->ClicksToExplode = LuaToNumber(l, -1);
} else if (!strcmp(value, "CanTransport")) {
// Warning: CanTransport should only be used AFTER all bool flags
// have been defined.
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument");
}
if (type->MaxOnBoard == 0) { // set default value.
type->MaxOnBoard = 1;
}
if (type->BoolFlag.size() < UnitTypeVar.GetNumberBoolFlag()) {
type->BoolFlag.resize(UnitTypeVar.GetNumberBoolFlag());
}
const int subargs = lua_rawlen(l, -1);
for (int k = 0; k < subargs; ++k) {
value = LuaToString(l, -1, k + 1);
++k;
const int index = UnitTypeVar.BoolFlagNameLookup[value];
if (index != -1) {
value = LuaToString(l, -1, k + 1);
type->BoolFlag[index].CanTransport = Ccl2Condition(l, value);
continue;
}
LuaError(l, "Unsupported flag tag for CanTransport: %s" _C_ value);
}
} else if (!strcmp(value, "CanGatherResources")) {
const int args = lua_rawlen(l, -1);
for (int j = 0; j < args; ++j) {
lua_rawgeti(l, -1, j + 1);
ResourceInfo *res = new ResourceInfo;
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument");
}
const int subargs = lua_rawlen(l, -1);
for (int k = 0; k < subargs; ++k) {
value = LuaToString(l, -1, k + 1);
++k;
if (!strcmp(value, "resource-id")) {
lua_rawgeti(l, -1, k + 1);
res->ResourceId = CclGetResourceByName(l);
lua_pop(l, 1);
type->ResInfo[res->ResourceId] = res;
} else if (!strcmp(value, "resource-step")) {
res->ResourceStep = LuaToNumber(l, -1, k + 1);
} else if (!strcmp(value, "final-resource")) {
lua_rawgeti(l, -1, k + 1);
res->FinalResource = CclGetResourceByName(l);
lua_pop(l, 1);
} else if (!strcmp(value, "wait-at-resource")) {
res->WaitAtResource = LuaToNumber(l, -1, k + 1);
} else if (!strcmp(value, "wait-at-depot")) {
res->WaitAtDepot = LuaToNumber(l, -1, k + 1);
} else if (!strcmp(value, "resource-capacity")) {
res->ResourceCapacity = LuaToNumber(l, -1, k + 1);
} else if (!strcmp(value, "terrain-harvester")) {
res->TerrainHarvester = 1;
--k;
} else if (!strcmp(value, "lose-resources")) {
res->LoseResources = 1;
--k;
} else if (!strcmp(value, "harvest-from-outside")) {
res->HarvestFromOutside = 1;
--k;
} else if (!strcmp(value, "refinery-harvester")) {
res->RefineryHarvester = 1;
--k;
} else if (!strcmp(value, "file-when-empty")) {
res->FileWhenEmpty = LuaToString(l, -1, k + 1);
} else if (!strcmp(value, "file-when-loaded")) {
res->FileWhenLoaded = LuaToString(l, -1, k + 1);
} else {
printf("\n%s\n", type->Name.c_str());
LuaError(l, "Unsupported tag: %s" _C_ value);
}
}
if (!res->FinalResource) {
res->FinalResource = res->ResourceId;
}
Assert(res->ResourceId);
lua_pop(l, 1);
}
type->BoolFlag[HARVESTER_INDEX].value = 1;
} else if (!strcmp(value, "GivesResource")) {
lua_pushvalue(l, -1);
type->GivesResource = CclGetResourceByName(l);
lua_pop(l, 1);
} else if (!strcmp(value, "CanStore")) {
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument");
}
const int subargs = lua_rawlen(l, -1);
for (int k = 0; k < subargs; ++k) {
lua_rawgeti(l, -1, k + 1);
type->CanStore[CclGetResourceByName(l)] = 1;
lua_pop(l, 1);
}
} else if (!strcmp(value, "CanCastSpell")) {
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument");
}
//
// Warning: can-cast-spell should only be used AFTER all spells
// have been defined. FIXME: MaxSpellType=500 or something?
//
if (!type->CanCastSpell) {
type->CanCastSpell = new char[SpellTypeTable.size()];
memset(type->CanCastSpell, 0, SpellTypeTable.size() * sizeof(char));
}
const int subargs = lua_rawlen(l, -1);
if (subargs == 0) {
delete[] type->CanCastSpell;
type->CanCastSpell = NULL;
}
for (int k = 0; k < subargs; ++k) {
value = LuaToString(l, -1, k + 1);
const SpellType *spell = SpellTypeByIdent(value);
if (spell == NULL) {
LuaError(l, "Unknown spell type: %s" _C_ value);
}
type->CanCastSpell[spell->Slot] = 1;
}
} else if (!strcmp(value, "AutoCastActive")) {
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument");
}
//
// Warning: AutoCastActive should only be used AFTER all spells
// have been defined.
//
if (!type->AutoCastActive) {
type->AutoCastActive = new char[SpellTypeTable.size()];
memset(type->AutoCastActive, 0, SpellTypeTable.size() * sizeof(char));
}
const int subargs = lua_rawlen(l, -1);
if (subargs == 0) {
delete[] type->AutoCastActive;
type->AutoCastActive = NULL;
}
for (int k = 0; k < subargs; ++k) {
value = LuaToString(l, -1, k + 1);
const SpellType *spell = SpellTypeByIdent(value);
if (spell == NULL) {
LuaError(l, "AutoCastActive : Unknown spell type: %s" _C_ value);
}
if (!spell->AutoCast) {
LuaError(l, "AutoCastActive : Define autocast method for %s." _C_ value);
}
type->AutoCastActive[spell->Slot] = 1;
}
} else if (!strcmp(value, "CanTargetFlag")) {
//
// Warning: can-target-flag should only be used AFTER all bool flags
// have been defined.
//
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument");
}
if (type->BoolFlag.size() < UnitTypeVar.GetNumberBoolFlag()) {
type->BoolFlag.resize(UnitTypeVar.GetNumberBoolFlag());
}
const int subargs = lua_rawlen(l, -1);
for (int k = 0; k < subargs; ++k) {
value = LuaToString(l, -1, k + 1);
++k;
int index = UnitTypeVar.BoolFlagNameLookup[value];
if (index != -1) {
value = LuaToString(l, -1, k + 1);
type->BoolFlag[index].CanTargetFlag = Ccl2Condition(l, value);
continue;
}
LuaError(l, "Unsupported flag tag for can-target-flag: %s" _C_ value);
}
} else if (!strcmp(value, "PriorityTarget")) {
//
// Warning: ai-priority-target should only be used AFTER all bool flags
// have been defined.
//
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument");
}
if (type->BoolFlag.size() < UnitTypeVar.GetNumberBoolFlag()) {
type->BoolFlag.resize(UnitTypeVar.GetNumberBoolFlag());
}
const int subargs = lua_rawlen(l, -1);
for (int k = 0; k < subargs; ++k) {
value = LuaToString(l, -1, k + 1);
++k;
int index = UnitTypeVar.BoolFlagNameLookup[value];
if (index != -1) {
value = LuaToString(l, -1, k + 1);
type->BoolFlag[index].AiPriorityTarget = Ccl2Condition(l, value);
continue;
}
LuaError(l, "Unsupported flag tag for ai-priority-target: %s" _C_ value);
}
} else if (!strcmp(value, "Sounds")) {
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument");
}
const int subargs = lua_rawlen(l, -1);
for (int k = 0; k < subargs; ++k) {
value = LuaToString(l, -1, k + 1);
++k;
if (!strcmp(value, "selected")) {
type->Sound.Selected.Name = LuaToString(l, -1, k + 1);
} else if (!strcmp(value, "acknowledge")) {
type->Sound.Acknowledgement.Name = LuaToString(l, -1, k + 1);
} else if (!strcmp(value, "attack")) {
type->Sound.Attack.Name = LuaToString(l, -1, k + 1);
} else if (!strcmp(value, "build")) {
type->Sound.Build.Name = LuaToString(l, -1, k + 1);
} else if (!strcmp(value, "ready")) {
type->Sound.Ready.Name = LuaToString(l, -1, k + 1);
} else if (!strcmp(value, "repair")) {
type->Sound.Repair.Name = LuaToString(l, -1, k + 1);
} else if (!strcmp(value, "harvest")) {
const std::string name = LuaToString(l, -1, k + 1);
++k;
const int resId = GetResourceIdByName(l, name.c_str());
type->Sound.Harvest[resId].Name = LuaToString(l, -1, k + 1);
} else if (!strcmp(value, "help")) {
type->Sound.Help.Name = LuaToString(l, -1, k + 1);
} else if (!strcmp(value, "work-complete")) {
type->Sound.WorkComplete.Name = LuaToString(l, -1, k + 1);
} else if (!strcmp(value, "dead")) {
int death;
const std::string name = LuaToString(l, -1, k + 1);
for (death = 0; death < ANIMATIONS_DEATHTYPES; ++death) {
if (name == ExtraDeathTypes[death]) {
++k;
break;
}
}
if (death == ANIMATIONS_DEATHTYPES) {
type->Sound.Dead[ANIMATIONS_DEATHTYPES].Name = name;
} else {
type->Sound.Dead[death].Name = LuaToString(l, -1, k + 1);
}
} else {
LuaError(l, "Unsupported sound tag: %s" _C_ value);
}
}
} else {
int index = UnitTypeVar.VariableNameLookup[value];
if (index != -1) { // valid index
if (lua_isboolean(l, -1)) {
type->DefaultStat.Variables[index].Enable = LuaToBoolean(l, -1);
} else if (lua_istable(l, -1)) {
DefineVariableField(l, type->DefaultStat.Variables + index, -1);
} else if (lua_isnumber(l, -1)) {
type->DefaultStat.Variables[index].Enable = 1;
type->DefaultStat.Variables[index].Value = LuaToNumber(l, -1);
type->DefaultStat.Variables[index].Max = LuaToNumber(l, -1);
} else { // Error
LuaError(l, "incorrect argument for the variable in unittype");
}
continue;
}
if (type->BoolFlag.size() < UnitTypeVar.GetNumberBoolFlag()) {
type->BoolFlag.resize(UnitTypeVar.GetNumberBoolFlag());
}
index = UnitTypeVar.BoolFlagNameLookup[value];
if (index != -1) {
if (lua_isnumber(l, -1)) {
type->BoolFlag[index].value = LuaToNumber(l, -1);
} else {
type->BoolFlag[index].value = LuaToBoolean(l, -1);
}
} else {
printf("\n%s\n", type->Name.c_str());
LuaError(l, "Unsupported tag: %s" _C_ value);
}
}
}
// If number of directions is not specified, make a guess
// Building have 1 direction and units 8
if (type->Building && type->NumDirections == 0) {
type->NumDirections = 1;
} else if (type->NumDirections == 0) {
type->NumDirections = 8;
}
// FIXME: try to simplify/combine the flags instead
if (type->MouseAction == MouseActionAttack && !type->CanAttack) {
LuaError(l, "Unit-type '%s': right-attack is set, but can-attack is not\n" _C_ type->Name.c_str());
}
UpdateDefaultBoolFlags(*type);
if (!CclInConfigFile) {
if (redefine & redefineSprite) {
LoadUnitTypeSprite(*type);
}
UpdateUnitStats(*type, 1);
}
return 0;
}
Description
Copy a unit type.
@param l Lua state.
Example:
CopyUnitType("unit-peasant", "unit-peasant-copy")
static int CclCopyUnitType(lua_State *l)
{
LuaCheckArgs(l, 2);
// Slot identifier
const char* fromName = LuaToString(l, 1);
CUnitType *from = UnitTypeByIdent(fromName);
const char* toName = LuaToString(l, 2);
CUnitType *to = UnitTypeByIdent(toName);
if (to) {
DebugPrint("Redefining unit-type '%s'\n" _C_ toName);
} else {
to = NewUnitTypeSlot(toName);
}
if (!from) {
LuaError(l, "Unknown unit-type '%s'\n" _C_ fromName);
}
to->Flip = from->Flip;
to->Name = toName;
to->File = from->File;
to->AltFile = from->AltFile;
to->Width = from->Width;
to->Height = from->Height;
if (to->Sprite) {
CGraphic::Free(to->Sprite);
to->Sprite = NULL;
}
if (to->AltSprite) {
CGraphic::Free(to->AltSprite);
to->AltSprite = NULL;
}
to->ShadowFile = from->ShadowFile;
to->ShadowWidth = from->ShadowWidth;
to->ShadowHeight = from->ShadowHeight;
to->ShadowOffsetX = from->ShadowOffsetX;
to->ShadowOffsetY = from->ShadowOffsetY;
to->ShadowSpriteFrame = from->ShadowSpriteFrame;
to->ShadowScale = from->ShadowScale;
if (to->ShadowSprite) {
CGraphic::Free(to->ShadowSprite);
to->ShadowSprite = NULL;
}
to->OffsetX = from->OffsetX;
to->OffsetY = from->OffsetY;
to->Animations = from->Animations;
to->Icon.Name = from->Icon.Name;
to->Icon.Icon = NULL;
#ifdef USE_MNG
to->Portrait.Num = from->Portrait.Num;
to->Portrait.Talking = from->Portrait.Talking;
to->Portrait.Files = new std::string[to->Portrait.Num];
for (int i = 0; i < to->Portrait.Num; i++) {
to->Portrait.Files[i] = from->Portrait.Files[i];
}
to->Portrait.Mngs = new Mng *[to->Portrait.Num];
memset(to->Portrait.Mngs, 0, to->Portrait.Num * sizeof(Mng *));
#endif
memcpy(to->DefaultStat.Costs, from->DefaultStat.Costs, sizeof(from->DefaultStat.Costs));
memcpy(to->DefaultStat.Storing, from->DefaultStat.Storing, sizeof(from->DefaultStat.Storing));
memcpy(to->DefaultStat.ImproveIncomes, from->DefaultStat.ImproveIncomes, sizeof(from->DefaultStat.ImproveIncomes));
to->Construction = from->Construction;
to->DrawLevel = from->DrawLevel;
to->MaxOnBoard = from->MaxOnBoard;
to->BoardSize = from->BoardSize;
to->ButtonLevelForTransporter = from->ButtonLevelForTransporter;
to->StartingResources = from->StartingResources;
to->DefaultStat.Variables[HP_INDEX].Increase = from->DefaultStat.Variables[HP_INDEX].Increase;
to->DefaultStat.Variables[HP_INDEX].IncreaseFrequency = from->DefaultStat.Variables[HP_INDEX].IncreaseFrequency;
to->BurnPercent = from->BurnPercent;
to->BurnDamageRate = from->BurnDamageRate;
to->PoisonDrain = from->PoisonDrain;
to->DefaultStat.Variables[SHIELD_INDEX].Max = from->DefaultStat.Variables[SHIELD_INDEX].Max;
to->DefaultStat.Variables[SHIELD_INDEX].Value = from->DefaultStat.Variables[SHIELD_INDEX].Value;
to->DefaultStat.Variables[SHIELD_INDEX].Increase = from->DefaultStat.Variables[SHIELD_INDEX].Increase;
to->DefaultStat.Variables[SHIELD_INDEX].Enable = from->DefaultStat.Variables[SHIELD_INDEX].Enable;
to->TileWidth = from->TileWidth;
to->TileHeight = from->TileHeight;
to->NeutralMinimapColorRGB = from->NeutralMinimapColorRGB;
to->Neutral = from->Neutral;
to->BoxWidth = from->BoxWidth;
to->BoxHeight = from->BoxHeight;
to->BoxOffsetX = from->BoxOffsetX;
to->BoxOffsetY = from->BoxOffsetY;
to->NumDirections = from->NumDirections;
to->ReactRangeComputer = from->ReactRangeComputer;
to->ReactRangePerson = from->ReactRangePerson;
to->Missile.Name = from->Missile.Name;
to->Missile.Missile = NULL; // filled in later
to->MinAttackRange = from->MinAttackRange;
to->DefaultStat.Variables[ATTACKRANGE_INDEX].Value = from->DefaultStat.Variables[ATTACKRANGE_INDEX].Value;
to->DefaultStat.Variables[ATTACKRANGE_INDEX].Max = from->DefaultStat.Variables[ATTACKRANGE_INDEX].Max;
to->DefaultStat.Variables[ATTACKRANGE_INDEX].Enable = from->DefaultStat.Variables[ATTACKRANGE_INDEX].Enable;
to->DefaultStat.Variables[MAXHARVESTERS_INDEX].Value = from->DefaultStat.Variables[MAXHARVESTERS_INDEX].Value;
to->DefaultStat.Variables[MAXHARVESTERS_INDEX].Max = from->DefaultStat.Variables[MAXHARVESTERS_INDEX].Max;
to->DefaultStat.Variables[PRIORITY_INDEX].Value = from->DefaultStat.Variables[PRIORITY_INDEX].Value;
to->DefaultStat.Variables[PRIORITY_INDEX].Max = from->DefaultStat.Variables[PRIORITY_INDEX].Max;
to->AnnoyComputerFactor = from->AnnoyComputerFactor;
to->AiAdjacentRange = from->AiAdjacentRange;
to->DecayRate = from->DecayRate;
to->CorpseName = from->CorpseName;
to->CorpseType = from->CorpseType;
to->DamageType = from->DamageType;
to->ExplodeWhenKilled = from->ExplodeWhenKilled;
to->Explosion.Name = from->Explosion.Name;
to->Explosion.Missile = NULL; // filled later
to->TeleportCost = from->TeleportCost;
to->TeleportEffectIn = from->TeleportEffectIn;
to->TeleportEffectOut = from->TeleportEffectOut;
to->OnDeath = from->OnDeath;
to->OnHit = from->OnHit;
to->OnEachCycle = from->OnEachCycle;
to->OnEachSecond = from->OnEachSecond;
to->OnInit = from->OnInit;
to->OnReady = from->OnReady;
to->UnitType = from->UnitType;
for (int k = 0; k < MaxAttackPos; ++k) {
for (int m = 0; m < UnitSides; ++m) {
to->MissileOffsets[m][k].x = from->MissileOffsets[m][k].x;
to->MissileOffsets[m][k].y = from->MissileOffsets[m][k].y;
}
}
for (int i = 0; i < ANIMATIONS_DEATHTYPES + 2; i++) {
to->Impact[i].Name = from->Impact[i].Name;
to->Impact[i].Missile = from->Impact[i].Missile;
}
to->MouseAction = from->MouseAction;
to->CanAttack = from->CanAttack;
to->RepairRange = from->RepairRange;
to->RepairHP = from->RepairHP;
memcpy(to->RepairCosts, from->RepairCosts, sizeof(from->RepairCosts));
to->CanTarget = from->CanTarget;
to->Building = from->Building;
to->BuildingRules.clear();
if (!from->BuildingRules.empty()) {
printf("WARNING: unit type copy %s of %s does not inherit BuildingRules\n", fromName, toName);
}
// XXX: should copy, not share, this will crash
// for (auto rule : from->BuildingRules) {
// to->BuildingRules.push_back(rule);
// }
to->AiBuildingRules.clear();
if (!from->AiBuildingRules.empty()) {
printf("WARNING: unit type copy %s of %s does not inherit AiBuildingRules\n", fromName, toName);
}
// XXX: should copy, not share, this would crash
// for (auto rule : from->AiBuildingRules) {
// to->AiBuildingRules.push_back(rule);
// }
to->AutoBuildRate = from->AutoBuildRate;
to->LandUnit = from->LandUnit;
to->AirUnit = from->AirUnit;
to->SeaUnit = from->SeaUnit;
to->RandomMovementProbability = from->RandomMovementProbability;
to->RandomMovementDistance = from->RandomMovementDistance;
to->ClicksToExplode = from->ClicksToExplode;
to->MaxOnBoard = from->MaxOnBoard;
for (unsigned int i = 0; i < from->BoolFlag.size(); i++) {
to->BoolFlag[i].value = from->BoolFlag[i].value;
to->BoolFlag[i].CanTransport = from->BoolFlag[i].CanTransport;
to->BoolFlag[i].CanTargetFlag = from->BoolFlag[i].CanTargetFlag;
to->BoolFlag[i].AiPriorityTarget = from->BoolFlag[i].AiPriorityTarget;
}
memcpy(to->ResInfo, from->ResInfo, sizeof(from->ResInfo));
to->GivesResource = from->GivesResource;
memcpy(to->CanStore, from->CanStore, sizeof(from->CanStore));
to->CanCastSpell = from->CanCastSpell;
to->AutoCastActive = from->AutoCastActive;
to->Sound.Selected.Name = from->Sound.Selected.Name;
to->Sound.Acknowledgement.Name = from->Sound.Acknowledgement.Name;
to->Sound.Attack.Name = from->Sound.Attack.Name;
to->Sound.Build.Name = from->Sound.Build.Name;
to->Sound.Ready.Name = from->Sound.Ready.Name;
to->Sound.Repair.Name = from->Sound.Repair.Name;
for (int i = 0; i < MaxCosts; i++) {
to->Sound.Harvest[i].Name = from->Sound.Harvest[i].Name;
}
to->Sound.Help.Name = from->Sound.Help.Name;
to->Sound.WorkComplete.Name = from->Sound.WorkComplete.Name;
for (unsigned int i = 0; i < ANIMATIONS_DEATHTYPES + 1; i++) {
to->Sound.Dead[i].Name = from->Sound.Dead[i].Name;
}
for (unsigned int i = 0; i < UnitTypeVar.GetNumberVariable(); i++) {
to->DefaultStat.Variables[i].Enable = from->DefaultStat.Variables[i].Enable;
to->DefaultStat.Variables[i].Value = from->DefaultStat.Variables[i].Value;
to->DefaultStat.Variables[i].Max = from->DefaultStat.Variables[i].Max;
to->DefaultStat.Variables[i].Increase = from->DefaultStat.Variables[i].Increase;
to->DefaultStat.Variables[i].IncreaseFrequency = from->DefaultStat.Variables[i].IncreaseFrequency;
}
UpdateDefaultBoolFlags(*to);
if (!CclInConfigFile) {
UpdateUnitStats(*to, 1);
}
LoadUnitTypes();
return 0;
}
Description
Parse unit-stats.
@param l Lua state.
Example:
DefineUnitStats("unit-berserker", 2, {
"HitPoints", {Value = 55, Max = 55, Increase = 0, Enable = true},
"AttackRange", {Value = 5, Max = 6, Increase = 0, Enable = true},
"SightRange", {Value = 7, Max = 7, Increase = 0, Enable = true},
})
static int CclDefineUnitStats(lua_State *l)
{
CUnitType *type = UnitTypeByIdent(LuaToString(l, 1));
const int playerId = LuaToNumber(l, 2);
Assert(type);
Assert(playerId < PlayerMax);
CUnitStats *stats = &type->Stats[playerId];
if (!stats->Variables) {
stats->Variables = new CVariable[UnitTypeVar.GetNumberVariable()];
}
// Parse the list: (still everything could be changed!)
const int args = lua_rawlen(l, 3);
for (int j = 0; j < args; ++j) {
const char *value = LuaToString(l, 3, j + 1);
++j;
if (!strcmp(value, "costs")) {
lua_rawgeti(l, 3, j + 1);
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument");
}
const int subargs = lua_rawlen(l, -1);
for (int k = 0; k < subargs; ++k) {
lua_rawgeti(l, 3, j + 1);
value = LuaToString(l, -1, k + 1);
++k;
const int resId = GetResourceIdByName(l, value);
stats->Costs[resId] = LuaToNumber(l, -1, k + 1);
lua_pop(l, 1);
}
} else if (!strcmp(value, "storing")) {
lua_rawgeti(l, 3, j + 1);
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument");
}
const int subargs = lua_rawlen(l, -1);
for (int k = 0; k < subargs; ++k) {
lua_rawgeti(l, 3, j + 1);
value = LuaToString(l, -1, k + 1);
++k;
const int resId = GetResourceIdByName(l, value);
stats->Storing[resId] = LuaToNumber(l, -1, k + 1);
lua_pop(l, 1);
}
} else if (!strcmp(value, "improve-production")) {
lua_rawgeti(l, 3, j + 1);
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument");
}
const int subargs = lua_rawlen(l, -1);
for (int k = 0; k < subargs; ++k) {
lua_rawgeti(l, 3, j + 1);
value = LuaToString(l, -1, k + 1);
++k;
const int resId = GetResourceIdByName(l, value);
stats->ImproveIncomes[resId] = LuaToNumber(l, -1, k + 1);
lua_pop(l, 1);
}
} else {
int i = UnitTypeVar.VariableNameLookup[value];// User variables
if (i != -1) { // valid index
lua_rawgeti(l, 3, j + 1);
if (lua_istable(l, -1)) {
DefineVariableField(l, stats->Variables + i, -1);
} else if (lua_isnumber(l, -1)) {
stats->Variables[i].Enable = 1;
stats->Variables[i].Value = LuaToNumber(l, -1);
stats->Variables[i].Max = LuaToNumber(l, -1);
} else { // Error
LuaError(l, "incorrect argument for the variable in unittype");
}
continue;
}
// This leaves a half initialized unit
LuaError(l, "Unsupported tag: %s" _C_ value);
}
}
return 0;
}
Define boolean flag.
@param l Lua state.
static int CclDefineBoolFlags(lua_State *l)
{
const unsigned int old = UnitTypeVar.GetNumberBoolFlag();
const int args = lua_gettop(l);
for (int j = 0; j < args; ++j) {
const char *str = LuaToString(l, j + 1);
UnitTypeVar.BoolFlagNameLookup.AddKey(str);
}
if (0 < old && old != UnitTypeVar.GetNumberBoolFlag()) {
size_t new_size = UnitTypeVar.GetNumberBoolFlag();
for (std::vector<CUnitType *>::size_type i = 0; i < UnitTypes.size(); ++i) { // adjust array for unit already defined
UnitTypes[i]->BoolFlag.resize(new_size);
}
}
return 0;
}
Define user variables.
@param l Lua state.
static int CclDefineVariables(lua_State *l)
{
int old = UnitTypeVar.GetNumberVariable();
const int args = lua_gettop(l);
for (int j = 0; j < args; ++j) {
const char *str = LuaToString(l, j + 1);
const int index = UnitTypeVar.VariableNameLookup.AddKey(str);
if (index == old) {
old++;
UnitTypeVar.Variable.resize(old);
} else {
DebugPrint("Warning, User Variable \"%s\" redefined\n" _C_ str);
}
if (!lua_istable(l, j + 2)) { // No change => default value.
continue;
}
++j;
DefineVariableField(l, &(UnitTypeVar.Variable[index]), j + 1);
}
return 0;
}
Define Decorations for user variables
@param l Lua state.
@todo modify Assert with luastate with User Error.
@todo continue to add configuration.
static int CclDefineDecorations(lua_State *l)
{
struct {
int Index;
int OffsetX;
int OffsetY;
int OffsetXPercent;
int OffsetYPercent;
bool IsCenteredInX;
bool IsCenteredInY;
bool ShowIfNotEnable;
bool ShowWhenNull;
bool HideHalf;
bool ShowWhenMax;
bool ShowOnlySelected;
bool HideNeutral;
bool HideAllied;
bool ShowOpponent;
bool BoolFlagInvert;
int BoolFlag;
} tmp;
const int nargs = lua_gettop(l);
for (int i = 0; i < nargs; i++) {
Assert(lua_istable(l, i + 1));
CDecoVar *decovar = NULL;
memset(&tmp, 0, sizeof(tmp));
lua_pushnil(l);
while (lua_next(l, i + 1)) {
const char *key = LuaToString(l, -2);
if (!strcmp(key, "Index")) {
const char *const value = LuaToString(l, -1);
tmp.Index = UnitTypeVar.VariableNameLookup[value];// User variables
Assert(tmp.Index != -1);
} else if (!strcmp(key, "Offset")) {
CclGetPos(l, &tmp.OffsetX, &tmp.OffsetY);
} else if (!strcmp(key, "OffsetPercent")) {
CclGetPos(l, &tmp.OffsetXPercent, &tmp.OffsetYPercent);
} else if (!strcmp(key, "CenterX")) {
tmp.IsCenteredInX = LuaToBoolean(l, -1);
} else if (!strcmp(key, "CenterY")) {
tmp.IsCenteredInY = LuaToBoolean(l, -1);
} else if (!strcmp(key, "ShowIfNotEnable")) {
tmp.ShowIfNotEnable = LuaToBoolean(l, -1);
} else if (!strcmp(key, "ShowWhenNull")) {
tmp.ShowWhenNull = LuaToBoolean(l, -1);
} else if (!strcmp(key, "HideHalf")) {
tmp.HideHalf = LuaToBoolean(l, -1);
} else if (!strcmp(key, "ShowWhenMax")) {
tmp.ShowWhenMax = LuaToBoolean(l, -1);
} else if (!strcmp(key, "ShowOnlySelected")) {
tmp.ShowOnlySelected = LuaToBoolean(l, -1);
} else if (!strcmp(key, "HideNeutral")) {
tmp.HideNeutral = LuaToBoolean(l, -1);
} else if (!strcmp(key, "HideAllied")) {
tmp.HideAllied = LuaToBoolean(l, -1);
} else if (!strcmp(key, "ShowOpponent")) {
tmp.ShowOpponent = LuaToBoolean(l, -1);
} else if (!strcmp(key, "Method")) {
Assert(lua_istable(l, -1));
lua_rawgeti(l, -1, 1); // MethodName
lua_rawgeti(l, -2, 2); // Data
Assert(lua_istable(l, -1));
key = LuaToString(l, -2);
if (!strcmp(key, "bar")) {
CDecoVarBar *decovarbar = new CDecoVarBar;
lua_pushnil(l);
while (lua_next(l, -2)) {
key = LuaToString(l, -2);
if (!strcmp(key, "Height")) {
decovarbar->Height = LuaToNumber(l, -1);
} else if (!strcmp(key, "Width")) {
decovarbar->Width = LuaToNumber(l, -1);
} else if (!strcmp(key, "MinValue")) {
decovarbar->MinValue = LuaToNumber(l, -1);
} else if (!strcmp(key, "MaxValue")) {
decovarbar->MaxValue = LuaToNumber(l, -1);
} else if (!strcmp(key, "Invert")) {
decovarbar->Invert = LuaToBoolean(l, -1);
} else if (!strcmp(key, "Orientation")) {
key = LuaToString(l, -1);
if (!strcmp(key, "horizontal")) {
decovarbar->IsVertical = 0;
} else if (!strcmp(key, "vertical")) {
decovarbar->IsVertical = 1;
} else { // Error
LuaError(l, "invalid Orientation '%s' for bar in DefineDecorations" _C_ key);
}
} else if (!strcmp(key, "SEToNW")) {
decovarbar->SEToNW = LuaToBoolean(l, -1);
} else if (!strcmp(key, "BorderSize")) {
decovarbar->BorderSize = LuaToNumber(l, -1);
} else if (!strcmp(key, "ShowFullBackground")) {
decovarbar->ShowFullBackground = LuaToBoolean(l, -1);
#if 0 // FIXME Color configuration
} else if (!strcmp(key, "Color")) {
decovar->Color = // FIXME
} else if (!strcmp(key, "BColor")) {
decovar->BColor = // FIXME
#endif
} else {
LuaError(l, "'%s' invalid for Method bar" _C_ key);
}
lua_pop(l, 1); // Pop value
}
decovar = decovarbar;
} else if (!strcmp(key, "frame")) {
CDecoVarFrame *frame = new CDecoVarFrame;
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument, need table with Thickness= and Color=");
}
for (lua_pushnil(l); lua_next(l, -2); lua_pop(l, 1)) {
const char* innerkey = LuaToString(l, -2);
if (!strcmp(innerkey, "Thickness")) {
frame->Thickness = LuaToNumber(l, -1);
} else if (!strcmp(innerkey, "ColorName")) {
const char *const colorName = LuaToString(l, -1);
frame->ColorIndex = GetColorIndexByName(colorName);
} else {
LuaError(l, "'%s' invalid for Method frame" _C_ innerkey);
}
}
decovar = frame;
} else if (!strcmp(key, "text")) {
CDecoVarText *decovartext = new CDecoVarText;
decovartext->Font = CFont::Get(LuaToString(l, -1, 1));
// FIXME : More arguments ? color...
decovar = decovartext;
} else if (!strcmp(key, "sprite")) {
CDecoVarSpriteBar *decovarspritebar = new CDecoVarSpriteBar;
decovarspritebar->NSprite = GetSpriteIndex(LuaToString(l, -1, 1));
if (decovarspritebar->NSprite == -1) {
LuaError(l, "invalid sprite-name '%s' for Method in DefineDecorations" _C_ LuaToString(l, -1, 1));
}
// FIXME : More arguments ?
decovar = decovarspritebar;
} else if (!strcmp(key, "static-sprite")) {
CDecoVarStaticSprite *decovarstaticsprite = new CDecoVarStaticSprite;
if (lua_rawlen(l, -1) == 2) {
decovarstaticsprite->NSprite = GetSpriteIndex(LuaToString(l, -1, 1));
decovarstaticsprite->n = LuaToNumber(l, -1, 2);
} else {
decovarstaticsprite->NSprite = GetSpriteIndex(LuaToString(l, -1, 1));
decovarstaticsprite->n = LuaToNumber(l, -1, 2);
decovarstaticsprite->FadeValue = LuaToNumber(l, -1, 3);
}
decovar = decovarstaticsprite;
} else if (!strcmp(key, "animated-sprite")) {
CDecoVarAnimatedSprite *decovarspritebar = new CDecoVarAnimatedSprite;
decovarspritebar->NSprite = GetSpriteIndex(LuaToString(l, -1, 1));
if (decovarspritebar->NSprite == -1) {
LuaError(l, "invalid sprite-name '%s' for Method in DefineDecorations" _C_ LuaToString(l, -1, 1));
}
decovarspritebar->WaitFrames = LuaToNumber(l, -1, 2);
if (decovarspritebar->WaitFrames <= 0) {
LuaError(l, "invalid wait-frames, must be > 0");
}
decovar = decovarspritebar;
} else { // Error
LuaError(l, "invalid method '%s' for Method in DefineDecorations" _C_ key);
}
lua_pop(l, 2); // MethodName and data
} else {
tmp.BoolFlag = UnitTypeVar.BoolFlagNameLookup[key];
if (tmp.BoolFlag != -1) {
tmp.BoolFlagInvert = LuaToBoolean(l, -1);
} else {
// Error
LuaError(l, "invalid key '%s' for DefineDecorations" _C_ key);
}
}
lua_pop(l, 1); // Pop the value
}
decovar->Index = tmp.Index;
decovar->OffsetX = tmp.OffsetX;
decovar->OffsetY = tmp.OffsetY;
decovar->OffsetXPercent = tmp.OffsetXPercent;
decovar->OffsetYPercent = tmp.OffsetYPercent;
decovar->IsCenteredInX = tmp.IsCenteredInX;
decovar->IsCenteredInY = tmp.IsCenteredInY;
decovar->ShowIfNotEnable = tmp.ShowIfNotEnable;
decovar->ShowWhenNull = tmp.ShowWhenNull;
decovar->HideHalf = tmp.HideHalf;
decovar->ShowWhenMax = tmp.ShowWhenMax;
decovar->ShowOnlySelected = tmp.ShowOnlySelected;
decovar->HideNeutral = tmp.HideNeutral;
decovar->HideAllied = tmp.HideAllied;
decovar->ShowOpponent = tmp.ShowOpponent;
decovar->BoolFlag = tmp.BoolFlag;
decovar->BoolFlagInvert = tmp.BoolFlagInvert;
UnitTypeVar.DecoVar.push_back(decovar);
}
Assert(lua_gettop(l));
return 0;
}
/unit/script_unittype.cpp:2297 CclDefinePaletteSwap
static int CclDefinePaletteSwap(lua_State *l)
{
LuaCheckArgs(l, 2);
const char *iconName = LuaToString(l, 1);
CIcon *icon = CIcon::Get(iconName);
if (!icon) {
LuaError(l, "icon %s not found" _C_ iconName);
}
if (!lua_istable(l, 2)) {
LuaError(l, "incorrect argument");
}
const int subargs = lua_rawlen(l, 2);
std::vector<PaletteSwap> newSwaps;
for (int k = 0; k < subargs; k += 2) {
const char *value = LuaToString(l, 2, k + 1);
int index = UnitTypeVar.VariableNameLookup[value];
if (index == -1) {
LuaError(l, "unknown variable name %s" _C_ value);
}
lua_rawgeti(l, 2, k + 2); // swap table
if (!lua_istable(l, -1) || lua_rawlen(l, -1) != 2) {
LuaError(l, "incorrect argument, need length 2 table with {startColorIndex, { ... color steps ... }");
}
int startColorIndex = LuaToNumber(l, -1, 1);
lua_rawgeti(l, -1, 2); // swap table, steps table
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument, need table with color steps");
}
int steps = lua_rawlen(l, -1);
std::vector<CColor> colors;
int colorCount = 0;
int alternativesCount = 0;
for (int step = 0; step < steps; step++) {
lua_rawgeti(l, -1, step + 1); // swap table, steps table, alternatives table
if (alternativesCount) {
if (lua_rawlen(l, -1) != alternativesCount) {
LuaError(l, "incorrect argument, need table with %d alternatives, got %zu" _C_ alternativesCount _C_ lua_rawlen(l, -1));
}
} else {
alternativesCount = lua_rawlen(l, -1);
}
for (int alt = 0; alt < alternativesCount; alt++) {
lua_rawgeti(l, -1, alt + 1); // swap table, steps table, alternatives table, color table
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument, need table with colors");
}
if (colorCount) {
if (lua_rawlen(l, -1) != colorCount) {
LuaError(l, "incorrect argument, need table with %d colors, got %zu" _C_ colorCount _C_ lua_rawlen(l, -1));
}
} else {
colorCount = lua_rawlen(l, -1);
}
for (int color = 0; color < colorCount; color++) {
lua_rawgeti(l, -1, color + 1);
CColor c;
c.Parse(l);
colors.push_back(c);
lua_pop(l, 1);
}
lua_pop(l, 1); // swap table, steps table, alternatives table
}
lua_pop(l, 1); // swap table, steps table
}
lua_pop(l, 1); // swap table
lua_pop(l, 1); // <emtpy>
newSwaps.emplace_back(index, startColorIndex, colorCount, steps, alternativesCount, colors);
}
icon->SetPaletteSwaps(newSwaps);
return 0;
}
Define default extra death types.
@param l Lua state.
static int CclDefineExtraDeathTypes(lua_State *l)
{
unsigned int args;
for (unsigned int i = 0; i < ANIMATIONS_DEATHTYPES; ++i) {
ExtraDeathTypes[i].clear();
}
args = lua_gettop(l);
for (unsigned int i = 0; i < ANIMATIONS_DEATHTYPES && i < args; ++i) {
ExtraDeathTypes[i] = LuaToString(l, i + 1);
}
return 0;
}
Get unit-type structure.
@param l Lua state.
@return Unit-type structure.
static int CclUnitType(lua_State *l)
{
LuaCheckArgs(l, 1);
const char *str = LuaToString(l, 1);
CUnitType *type = UnitTypeByIdent(str);
LuaUserData *data = (LuaUserData *)lua_newuserdata(l, sizeof(LuaUserData));
data->Type = LuaUnitType;
data->Data = type;
return 1;
}
Get all unit-type structures.
@param l Lua state.
@return An array of all unit-type structures.
static int CclUnitTypeArray(lua_State *l)
{
LuaCheckArgs(l, 0);
lua_newtable(l);
for (std::vector<CUnitType *>::size_type i = 0; i < UnitTypes.size(); ++i) {
LuaUserData *data = (LuaUserData *)lua_newuserdata(l, sizeof(LuaUserData));
data->Type = LuaUnitType;
data->Data = UnitTypes[i];
lua_rawseti(l, 1, i + 1);
}
return 1;
}
Get the ident of the unit-type structure.
@param l Lua state.
@return The identifier of the unit-type.
static int CclGetUnitTypeIdent(lua_State *l)
{
LuaCheckArgs(l, 1);
const CUnitType *type = CclGetUnitType(l);
if (type) {
lua_pushstring(l, type->Ident.c_str());
} else {
LuaError(l, "unit '%s' not defined" _C_ LuaToString(l, -1));
}
return 1;
}
Description
Get the name of the unit-type structure.
@param l Lua state.
@return The name of the unit-type.
Example:
name = GetUnitTypeName("unit-knight")
print(name)
static int CclGetUnitTypeName(lua_State *l)
{
LuaCheckArgs(l, 1);
const CUnitType *type = CclGetUnitType(l);
lua_pushstring(l, type->Name.c_str());
return 1;
}
Description
Set the name of the unit-type structure.
@param l Lua state.
@return The name of the unit-type.
Example:
SetUnitTypeName("unit-beast-cry","Doomhammer")
static int CclSetUnitTypeName(lua_State *l)
{
LuaCheckArgs(l, 2);
lua_pushvalue(l, 1);
CUnitType *type = CclGetUnitType(l);
lua_pop(l, 1);
type->Name = LuaToString(l, 2);
lua_pushvalue(l, 2);
return 1;
}
Description
Get unit type data.
@param l Lua state.
Example:
-- Get the amount of supply from Human Farms
supply = GetUnitTypeData("unit-farm","Supply")
print(supply)
static int CclGetUnitTypeData(lua_State *l)
{
if (lua_gettop(l) < 2) {
LuaError(l, "incorrect argument");
}
lua_pushvalue(l, 1);
const CUnitType *type = CclGetUnitType(l);
lua_pop(l, 1);
const char *data = LuaToString(l, 2);
if (!strcmp(data, "Name")) {
lua_pushstring(l, type->Name.c_str());
return 1;
} else if (!strcmp(data, "Icon")) {
lua_pushstring(l, type->Icon.Name.c_str());
return 1;
} else if (!strcmp(data, "Costs")) {
LuaCheckArgs(l, 3);
const std::string res = LuaToString(l, 3);
const int resId = GetResourceIdByName(l, res.c_str());
if (!GameRunning && Editor.Running != EditorEditing) {
lua_pushnumber(l, type->DefaultStat.Costs[resId]);
} else {
lua_pushnumber(l, type->MapDefaultStat.Costs[resId]);
}
return 1;
} else if (!strcmp(data, "ImproveProduction")) {
LuaCheckArgs(l, 3);
const std::string res = LuaToString(l, 3);
const int resId = GetResourceIdByName(l, res.c_str());
if (!GameRunning && Editor.Running != EditorEditing) {
lua_pushnumber(l, type->DefaultStat.ImproveIncomes[resId]);
} else {
lua_pushnumber(l, type->MapDefaultStat.ImproveIncomes[resId]);
}
return 1;
} else if (!strcmp(data, "DrawLevel")) {
lua_pushnumber(l, type->DrawLevel);
return 1;
} else if (!strcmp(data, "TileWidth")) {
lua_pushnumber(l, type->TileWidth);
return 1;
} else if (!strcmp(data, "TileHeight")) {
lua_pushnumber(l, type->TileHeight);
return 1;
} else if (!strcmp(data, "ComputerReactionRange")) {
lua_pushnumber(l, type->ReactRangeComputer);
return 1;
} else if (!strcmp(data, "PersonReactionRange")) {
lua_pushnumber(l, type->ReactRangePerson);
return 1;
} else if (!strcmp(data, "Missile")) {
lua_pushstring(l, type->Missile.Name.c_str());
return 1;
} else if (!strcmp(data, "MinAttackRange")) {
lua_pushnumber(l, type->MinAttackRange);
return 1;
} else if (!strcmp(data, "MaxAttackRange")) {
if (!GameRunning && Editor.Running != EditorEditing) {
lua_pushnumber(l, type->DefaultStat.Variables[ATTACKRANGE_INDEX].Value);
} else {
lua_pushnumber(l, type->MapDefaultStat.Variables[ATTACKRANGE_INDEX].Value);
}
return 1;
} else if (!strcmp(data, "Priority")) {
if (!GameRunning && Editor.Running != EditorEditing) {
lua_pushnumber(l, type->DefaultStat.Variables[PRIORITY_INDEX].Value);
} else {
lua_pushnumber(l, type->MapDefaultStat.Variables[PRIORITY_INDEX].Value);
}
return 1;
} else if (!strcmp(data, "Type")) {
if (type->UnitType == UnitTypeLand) {
lua_pushstring(l, "land");
return 1;
} else if (type->UnitType == UnitTypeFly) {
lua_pushstring(l, "fly");
return 1;
} else if (type->UnitType == UnitTypeNaval) {
lua_pushstring(l, "naval");
return 1;
}
} else if (!strcmp(data, "Corpse")) {
lua_pushstring(l, type->CorpseName.c_str());
return 1;
} else if (!strcmp(data, "CanAttack")) {
lua_pushboolean(l, type->CanAttack);
return 1;
} else if (!strcmp(data, "Building")) {
lua_pushboolean(l, type->Building);
return 1;
} else if (!strcmp(data, "LandUnit")) {
lua_pushboolean(l, type->LandUnit);
return 1;
} else if (!strcmp(data, "GivesResource")) {
if (type->GivesResource > 0) {
lua_pushstring(l, DefaultResourceNames[type->GivesResource].c_str());
return 1;
} else {
lua_pushstring(l, "");
return 1;
}
} else if (!strcmp(data, "Sounds")) {
LuaCheckArgs(l, 3);
const std::string sound_type = LuaToString(l, 3);
if (sound_type == "selected") {
if (!GameRunning && Editor.Running != EditorEditing) {
lua_pushstring(l, type->Sound.Selected.Name.c_str());
} else {
lua_pushstring(l, type->MapSound.Selected.Name.c_str());
}
} else if (sound_type == "acknowledge") {
if (!GameRunning && Editor.Running != EditorEditing) {
lua_pushstring(l, type->Sound.Acknowledgement.Name.c_str());
} else {
lua_pushstring(l, type->MapSound.Acknowledgement.Name.c_str());
}
} else if (sound_type == "attack") {
if (!GameRunning && Editor.Running != EditorEditing) {
lua_pushstring(l, type->Sound.Attack.Name.c_str());
} else {
lua_pushstring(l, type->MapSound.Attack.Name.c_str());
}
} else if (sound_type == "build") {
if (!GameRunning && Editor.Running != EditorEditing) {
lua_pushstring(l, type->Sound.Build.Name.c_str());
} else {
lua_pushstring(l, type->MapSound.Build.Name.c_str());
}
} else if (sound_type == "ready") {
if (!GameRunning && Editor.Running != EditorEditing) {
lua_pushstring(l, type->Sound.Ready.Name.c_str());
} else {
lua_pushstring(l, type->MapSound.Ready.Name.c_str());
}
} else if (sound_type == "repair") {
if (!GameRunning && Editor.Running != EditorEditing) {
lua_pushstring(l, type->Sound.Repair.Name.c_str());
} else {
lua_pushstring(l, type->MapSound.Repair.Name.c_str());
}
} else if (sound_type == "harvest") {
LuaCheckArgs(l, 4);
const std::string sound_subtype = LuaToString(l, 4);
const int resId = GetResourceIdByName(sound_subtype.c_str());
if (!GameRunning && Editor.Running != EditorEditing) {
lua_pushstring(l, type->Sound.Harvest[resId].Name.c_str());
} else {
lua_pushstring(l, type->MapSound.Harvest[resId].Name.c_str());
}
} else if (sound_type == "help") {
if (!GameRunning && Editor.Running != EditorEditing) {
lua_pushstring(l, type->Sound.Help.Name.c_str());
} else {
lua_pushstring(l, type->MapSound.Help.Name.c_str());
}
} else if (sound_type == "dead") {
if (lua_gettop(l) < 4) {
if (!GameRunning && Editor.Running != EditorEditing) {
lua_pushstring(l, type->Sound.Dead[ANIMATIONS_DEATHTYPES].Name.c_str());
} else {
lua_pushstring(l, type->MapSound.Dead[ANIMATIONS_DEATHTYPES].Name.c_str());
}
} else {
int death;
const std::string sound_subtype = LuaToString(l, 4);
for (death = 0; death < ANIMATIONS_DEATHTYPES; ++death) {
if (sound_subtype == ExtraDeathTypes[death]) {
break;
}
}
if (death == ANIMATIONS_DEATHTYPES) {
if (!GameRunning && Editor.Running != EditorEditing) {
lua_pushstring(l, type->Sound.Dead[ANIMATIONS_DEATHTYPES].Name.c_str());
} else {
lua_pushstring(l, type->MapSound.Dead[ANIMATIONS_DEATHTYPES].Name.c_str());
}
} else {
if (!GameRunning && Editor.Running != EditorEditing) {
lua_pushstring(l, type->Sound.Dead[death].Name.c_str());
} else {
lua_pushstring(l, type->MapSound.Dead[death].Name.c_str());
}
}
}
}
return 1;
} else {
int index = UnitTypeVar.VariableNameLookup[data];
if (index != -1) { // valid index
if (!GameRunning && Editor.Running != EditorEditing) {
lua_pushnumber(l, type->DefaultStat.Variables[index].Value);
} else {
lua_pushnumber(l, type->MapDefaultStat.Variables[index].Value);
}
return 1;
}
index = UnitTypeVar.BoolFlagNameLookup[data];
if (index != -1) {
lua_pushboolean(l, type->BoolFlag[index].value);
return 1;
} else {
LuaError(l, "Invalid field: %s" _C_ data);
}
}
return 0;
}
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;
}
Description
Get the list of shaders.
Example:
shaders = GetShaderNames()
for i,name in ipairs(shaders) do
print(name)
end
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;
}
Description
Get the active shader.
Example:
shader_name = GetShader()
print(shader_name)
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;
}
Description
Apply a shader.
Example:
-- Apply a VHS shader
SetShader("VHS")
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;
}
Set the video sync speed
@param l Lua state.
static int CclSetVideoSyncSpeed(lua_State *l)
{
LuaCheckArgs(l, 1);
VideoSyncSpeed = LuaToNumber(l, 1);
return 0;
}
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;
}
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;
}
Description
Set the cut off distance.
@param l Lua state.
Example:
SetGlobalSoundRange(200)
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;
}
Description
Ask the sound system to play the specified sound.
@param l Lua state.
Example:
PlaySound("rescue (orc)")
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;
}
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, 1);
MapRevealModes newMode;
const char *revealMode = LuaToString(l, 1);
if (!strcmp(revealMode, "hidden")) {
newMode = MapRevealModes::cHidden;
} else if (!strcmp(revealMode, "known")) {
newMode = MapRevealModes::cKnown;
} else if (!strcmp(revealMode, "explored")) {
newMode = MapRevealModes::cExplored;
} else {
PrintFunction();
fprintf(stdout, "Accessible reveal modes: \"hidden\", \"known\", \"explored\".\n");
return 1;
}
if (CclInConfigFile || !Map.Fields) {
FlagRevealMap = newMode;
} else if (!IsNetworkGame()) {
Map.Reveal(newMode);
} else {
NetworkSendExtendedCommand(ExtendedMessageRevealMapDB, int(newMode), 0, 0, 0, 0);
}
return 0;
}
Description
Center the map.
@param l Lua state.
Example:
-- Center the view at position x=11 and y=1.
CenterMap(11, 1)
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;
}
Description
Define the starting viewpoint for a given player.
@param l Lua state.
Example:
-- Start view for player 0.
SetStartView(0, 25, 12)
-- Start view for player 1.
SetStartView(1, 71, 38)
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, 5);
const char *unitname = LuaToString(l, 5);
CUnitType *unitType = UnitTypeByIdent(unitname);
if (!unitType) {
DebugPrint("Unable to find UnitType '%s'" _C_ unitname);
return 0;
}
CUnit *target = MakeUnit(*unitType, ThisPlayer);
if (target != NULL) {
target->Variable[HP_INDEX].Value = 0;
target->tilePos.x = LuaToNumber(l, 1);
target->tilePos.y = LuaToNumber(l, 2);
target->TTL = GameCycle + LuaToNumber(l, 4);
target->CurrentSightRange = LuaToNumber(l, 3);
MapMarkUnitSight(*target);
} else {
DebugPrint("Unable to allocate Unit");
}
return 0;
}
Description
Define size in pixels (x,y) of a tile in this game
@param l Lua state.
Example:
SetTileSize(32,32)
static int CclSetTileSize(lua_State *l)
{
LuaCheckArgs(l, 2);
PixelTileSize.x = LuaToNumber(l, 1);
PixelTileSize.y = LuaToNumber(l, 2);
return 0;
}
Description
Set fog of war on/off.
Example:
SetFogOfWar(true)
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;
}
Description
Get if the fog of war is enabled.
@param l Lua state.
Example:
GetFogOfWar()
static int CclGetFogOfWar(lua_State *l)
{
LuaCheckArgs(l, 0);
lua_pushboolean(l, !Map.NoFogOfWar);
return 1;
}
Description
Enable display of terrain in minimap.
@param l Lua state.
Example:
-- Show the minimap terrain
SetMinimapTerrain(true)
static int CclSetMinimapTerrain(lua_State *l)
{
LuaCheckArgs(l, 1);
UI.Minimap.WithTerrain = LuaToBoolean(l, 1);
return 0;
}
Activate map grid (true|false)
@param l Lua state.
@return 0 for success, 1 for wrong type;
static int CclSetEnableMapGrid(lua_State *l)
{
LuaCheckArgs(l, 1);
CViewport::EnableGrid(LuaToBoolean(l, 1));
return 0;
}
Check if map grid is enabled
static int CclGetIsMapGridEnabled(lua_State *l)
{
LuaCheckArgs(l, 0);
lua_pushboolean(l, CViewport::isGridEnabled());
return 1;
}
Select unit's field of view algorithm - ShadowCasting or SimpleRadial
@param l Lua state.
@return 0 for success, 1 for wrong type;
static int CclSetFieldOfViewType(lua_State *l)
{
LuaCheckArgs(l, 1);
FieldOfViewTypes new_type;
const char *type_name = LuaToString(l, 1);
if (!strcmp(type_name, "shadow-casting")) {
new_type = FieldOfViewTypes::cShadowCasting;
/// Tiled types of FOW don't work with shadow casting
if (FogOfWar->GetType() != FogOfWarTypes::cEnhanced) {
FogOfWar->SetType(FogOfWarTypes::cEnhanced);
}
} else if (!strcmp(type_name, "simple-radial")) {
new_type = FieldOfViewTypes::cSimpleRadial;
} else {
PrintFunction();
fprintf(stdout, "Accessible Field of View types: \"shadow-casting\", \"simple-radial\".\n");
return 1;
}
if (!IsNetworkGame()) {
FieldOfView.SetType(new_type);
} else {
NetworkSendExtendedCommand(ExtendedMessageFieldOfViewDB, int(new_type), 0, 0, 0, 0);
}
return 0;
}
Get unit's field of view type - ShadowCasting or SimpleRadial
static int CclGetFieldOfViewType(lua_State *l)
{
LuaCheckArgs(l, 0);
lua_pushinteger(l, int(FieldOfView.GetType()));
return 1;
}
Set opaque for the tile's terrain.
@param l Lua state.
@return 0 for success, 1 for wrong tile's terrain;
static int CclSetOpaqueFor(lua_State *l)
{
uint16_t new_flag = 0;
const int args = lua_gettop(l);
if (args < 1) {
LuaError(l, "argument missed");
return 1;
}
for (int arg = 0; arg < args; ++arg) {
const char *flag_name = LuaToString(l, arg + 1);
if (!strcmp(flag_name, "wall")) {
new_flag |= MapFieldWall;
} else if (!strcmp(flag_name, "rock")) {
new_flag |= MapFieldRocks;
} else if (!strcmp(flag_name, "forest")) {
new_flag |= MapFieldForest;
} else {
PrintFunction();
fprintf(stdout, "Opaque can only be set for \"wall\", \"rock\" or \"forest\". \n");
return 1;
}
}
if (!IsNetworkGame()) {
FieldOfView.SetOpaqueFields(FieldOfView.GetOpaqueFields() | new_flag);
} else {
NetworkSendExtendedCommand(ExtendedMessageMapFieldsOpacityDB, 0,
FieldOfView.GetOpaqueFields() | new_flag, 0, 0, 0);
}
return 0;
}
/map/script_map.cpp:469 CclRemoveOpaqueFor
static int CclRemoveOpaqueFor(lua_State *l)
{
unsigned short new_flag = 0;
const int args = lua_gettop(l);
if (args < 1) {
LuaError(l, "argument missed");
return 1;
}
for (int arg = 0; arg < args; ++arg) {
const char *flag_name = LuaToString(l, arg + 1);
if (!strcmp(flag_name, "wall")) {
new_flag |= MapFieldWall;
} else if (!strcmp(flag_name, "rock")) {
new_flag |= MapFieldRocks;
} else if (!strcmp(flag_name, "forest")) {
new_flag |= MapFieldForest;
} else {
PrintFunction();
fprintf(stdout, "Opaque can only be removed for \"wall\", \"rock\" or \"forest\". \n");
return 1;
}
}
if (!IsNetworkGame()) {
FieldOfView.SetOpaqueFields(FieldOfView.GetOpaqueFields() & ~new_flag);
} else {
NetworkSendExtendedCommand(ExtendedMessageMapFieldsOpacityDB, 0,
FieldOfView.GetOpaqueFields() & ~new_flag, 0, 0, 0);
}
return 0;
}
Check opacity for the tile's terrain.
@param l Lua state.
static int CclGetIsOpaqueFor(lua_State *l)
{
LuaCheckArgs(l, 1);
uint16_t flagToCheck = 0;
const char *flag_name = LuaToString(l, 1);
if (!strcmp(flag_name, "wall")) {
flagToCheck = MapFieldWall;
} else if (!strcmp(flag_name, "rock")) {
flagToCheck = MapFieldRocks;
} else if (!strcmp(flag_name, "forest")) {
flagToCheck = MapFieldForest;
} else {
PrintFunction();
fprintf(stdout, "Opaque can only be checked for \"wall\", \"rock\" or \"forest\". \n");
}
lua_pushboolean(l, FieldOfView.GetOpaqueFields() & flagToCheck);
return 1;
}
Select which type of Fog of War to use
@param l Lua state.
@return 0 for success, 1 for wrong type;
static int CclSetFogOfWarType(lua_State *l)
{
LuaCheckArgs(l, 1);
FogOfWarTypes new_type;
const std::string type_name {LuaToString(l, 1)};
if (type_name == "tiled" || type_name == "fast") {
new_type = type_name == "tiled" ? FogOfWarTypes::cTiled : FogOfWarTypes::cTiledLegacy;
/// Tiled types of FOW don't work with shadow casting
if (FieldOfView.GetType() == FieldOfViewTypes::cShadowCasting) {
if (!IsNetworkGame()) {
FieldOfView.SetType(FieldOfViewTypes::cSimpleRadial);
} else {
NetworkSendExtendedCommand(ExtendedMessageFieldOfViewDB,
int(FieldOfViewTypes::cSimpleRadial), 0, 0, 0, 0);
}
}
} else if (type_name == "enhanced") {
new_type = FogOfWarTypes::cEnhanced;
} else {
PrintFunction();
fprintf(stdout, "Accessible Fog of War types: \"tiled\", \"enhanced\" and \"fast\".\n");
return 1;
}
FogOfWar->SetType(new_type);
return 0;
}
Get Fog of War type - legacy or enhanced
static int CclGetFogOfWarType(lua_State *l)
{
LuaCheckArgs(l, 0);
lua_pushinteger(l, int(FogOfWar->GetType()));
return 1;
}
Set opacity (alpha) for different levels of fog of war - explored, revealed, unseen
@param l Lua state.
@return 0 for success, 1 for wrong type;
static int CclSetFogOfWarOpacityLevels(lua_State *l)
{
LuaCheckArgs(l, 3);
const int explored = LuaToNumber(l, 1);
if (explored <= 0 || explored > 255) {
PrintFunction();
fprintf(stderr, "Invalid value (%d) of opacity for Explored tiles. Acceptable range is [0 <= Explored <= Known <= Hidden <= 255].\n", explored);
return 1;
}
const int revealed = LuaToNumber(l, 2);
if (revealed <= explored || revealed > 255) {
PrintFunction();
fprintf(stderr, "Invalid value (%d) of opacity for Revealed tiles. Acceptable range is [0 <= Explored <= Known <= Hidden <= 255].\n", revealed);
return 1;
}
const int unseen = LuaToNumber(l, 3);
if (unseen < revealed || unseen > 255) {
PrintFunction();
fprintf(stderr, "Invalid value (%d) of opacity for Unseen tiles. Acceptable range is [0 <= Explored <= Known <= Hidden <= 255].\n", unseen);
return 1;
}
FogOfWar->SetOpacityLevels(explored, revealed, unseen);
return 0;
}
Set parameters for FOW blurer (radiuses and number of iterations)
@param l Lua state.
@return 0 for success, 1 for wrong type;
static int CclSetFogOfWarBlur(lua_State *l)
{
LuaCheckArgs(l, 3);
const float radiusSimple = LuaToFloat(l, 1);
if (radiusSimple <= 0 ) {
PrintFunction();
fprintf(stdout, "Radius should be a positive float number. Blur is disabled.\n");
}
const float radiusBilinear = LuaToFloat(l, 2);
if (radiusBilinear <= 0 ) {
PrintFunction();
fprintf(stdout, "Radius should be a positive float number. Blur is disabled.\n");
}
const int iterations = LuaToNumber(l, 3);
if (iterations <= 0 ) {
PrintFunction();
fprintf(stdout, "Number of box blur iterations should be greater than 0. Blur is disabled.\n");
}
FogOfWar->InitBlurer(radiusSimple, radiusBilinear, iterations);
return 0;
}
Activate FOW bilinear upscaling type (true|false)
@param l Lua state.
@return 0 for success, 1 for wrong type;
static int CclSetFogOfWarBilinear(lua_State *l)
{
LuaCheckArgs(l, 1);
FogOfWar->EnableBilinearUpscale(LuaToBoolean(l, 1));
return 0;
}
Check if FOW bilinear upscaling enabled
static int CclGetIsFogOfWarBilinear(lua_State *l)
{
LuaCheckArgs(l, 0);
lua_pushboolean(l, FogOfWar->IsBilinearUpscaleEnabled());
return 1;
}
Define Fog graphics
@param l Lua state.
static int CclSetFogOfWarGraphics(lua_State *l)
{
std::string FogGraphicFile;
LuaCheckArgs(l, 1);
FogGraphicFile = LuaToString(l, 1);
CFogOfWar::SetTiledFogGraphic(FogGraphicFile);
return 0;
}
Description
Set Fog color.
@param l Lua state.
Example:
-- Red fog of war
SetFogOfWarColor(128,0,0)
static int CclSetFogOfWarColor(lua_State *l)
{
LuaCheckArgs(l, 3);
int r = LuaToNumber(l, 1);
int g = LuaToNumber(l, 2);
int b = LuaToNumber(l, 3);
if ((r < 0 || r > 255) ||
(g < 0 || g > 255) ||
(b < 0 || b > 255)) {
LuaError(l, "Arguments must be in the range 0-255");
}
FogOfWar->SetFogColor(r, g, b);
return 0;
}
Set opacity (alpha) for different levels of fog of war - explored, revealed, unexplored for mini map
@param l Lua state.
@return 0 for success, 1 for wrong type;
static int CclSetMMFogOfWarOpacityLevels(lua_State *l)
{
LuaCheckArgs(l, 3);
const int explored = LuaToNumber(l, 1);
if (explored <= 0 || explored > 255) {
PrintFunction();
fprintf(stderr, "Invalid value (%d) of opacity for Minimap's Explored tiles. Acceptable range is [0 <= Explored <= Known <= Hidden <= 255].\n", explored);
return 1;
}
const int revealed = LuaToNumber(l, 2);
if (revealed <= explored || revealed > 255) {
PrintFunction();
fprintf(stderr, "Invalid value (%d) of opacity for Minimap's Revealed tiles. Acceptable range is [0 <= Explored <= Known <= Hidden <= 255].\n", revealed);
return 1;
}
const int unseen = LuaToNumber(l, 3);
if (unseen < revealed || unseen > 255) {
PrintFunction();
fprintf(stderr, "Invalid value (%d) of opacity for Minimap's Unseen tiles. Acceptable range is [0 <= Explored <= Known <= Hidden <= 255].\n", unseen);
return 1;
}
UI.Minimap.SetFogOpacityLevels(explored, revealed, unseen);
return 0;
}
Description
Set forest regeneration speed.
@param l Lua state.
@return Old speed
Example:
-- No regeneration.
SetForestRegeneration(0)
-- Slow regeneration every 50 seconds
SetForestRegeneration(50)
-- Extremely slow regeneration every 1h of game time
SetForestRegeneration(3600)
static int CclSetForestRegeneration(lua_State *l)
{
LuaCheckArgs(l, 1);
int i = LuaToNumber(l, 1);
int frequency = 1;
if (i < 0) {
LuaError(l, "Regeneration speed should be >= 0\n");
}
while (i / frequency > 255) {
frequency++;
}
i = i / frequency;
const int old = ForestRegeneration * ForestRegenerationFrequency;
ForestRegeneration = i;
ForestRegenerationFrequency = frequency;
lua_pushnumber(l, old);
return 1;
}
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] = PlayerTypes::PlayerNeutral;
} else if (!strcmp(type, "nobody")) {
Map.Info.PlayerType[i] = PlayerTypes::PlayerNobody;
} else if (!strcmp(type, "computer")) {
Map.Info.PlayerType[i] = PlayerTypes::PlayerComputer;
} else if (!strcmp(type, "person")) {
Map.Info.PlayerType[i] = PlayerTypes::PlayerPerson;
} else if (!strcmp(type, "rescue-passive")) {
Map.Info.PlayerType[i] = PlayerTypes::PlayerRescuePassive;
} else if (!strcmp(type, "rescue-active")) {
Map.Info.PlayerType[i] = PlayerTypes::PlayerRescueActive;
} else {
LuaError(l, "Unsupported tag: %s" _C_ type);
}
}
for (int i = numplayers; i < PlayerMax - 1; ++i) {
Map.Info.PlayerType[i] = PlayerTypes::PlayerNobody;
}
if (numplayers < PlayerMax) {
Map.Info.PlayerType[PlayerMax - 1] = PlayerTypes::PlayerNeutral;
}
return 0;
}
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));
if (pos.x >= Map.Info.MapWidth || pos.y >= Map.Info.MapHeight || pos.x < 0 || pos.y < 0) {
// out of bounds, doesn't have it
lua_pushboolean(l, 0);
return 1;
}
unsigned short flag = 0;
const char *flag_name = LuaToString(l, 3);
if (!strcmp(flag_name, "opaque")) {
flag = MapFieldOpaque;
} else if (!strcmp(flag_name, "water")) {
flag = MapFieldWaterAllowed;
} else if (!strcmp(flag_name, "land")) {
flag = MapFieldLandAllowed;
} else if (!strcmp(flag_name, "coast")) {
flag = MapFieldCoastAllowed;
} else if (!strcmp(flag_name, "no-building")) {
flag = MapFieldNoBuilding;
} else if (!strcmp(flag_name, "unpassable")) {
flag = MapFieldUnpassable;
} else if (!strcmp(flag_name, "wall")) {
flag = MapFieldWall;
} else if (!strcmp(flag_name, "rock")) {
flag = MapFieldRocks;
} else if (!strcmp(flag_name, "forest")) {
flag = MapFieldForest;
}
const CMapField &mf = *Map.Field(pos);
if (mf.getFlag() & flag) {
lua_pushboolean(l, 1);
} else {
lua_pushboolean(l, 0);
}
return 1;
}
Enable walls enabled for single player games (for debug purposes)
@param l Lua state.
@return 0 for success, 1 for wrong type;
static int CclSetEnableWallsForSP(lua_State *l)
{
LuaCheckArgs(l, 1);
EnableWallsInSinglePlayer = LuaToBoolean(l, 1);
return 0;
}
Check if walls enabled for single player games (for debug purposes)
static int CclIsWallsEnabledForSP(lua_State *l)
{
LuaCheckArgs(l, 0);
lua_pushboolean(l, EnableWallsInSinglePlayer);
return 1;
}
Check if network game was created on this PC
static int CclGetIsGameHoster(lua_State *l)
{
LuaCheckArgs(l, 0);
lua_pushboolean(l, (ThisPlayer->Index == Hosts[0].PlyNr) ? true : false);
return 1;
}
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;
}
Description
Change all units owned by one player or change only specific units owned by one player
@param l Lua state.
Example:
-- Changes all units owned by player 0 and give to player 1
ChangeUnitsOwner({16, 17}, {30, 32}, 0, 1)
-- Changes all farms owned by player 0 and give to player 1
ChangeUnitsOwner({16, 17}, {30, 32}, 0, 1, "unit-farm")
static int CclChangeUnitsOwner(lua_State *l)
{
int args = lua_gettop(l);
if (args != 4 && args != 5) {
LuaError(l, "incorrect argument count, need 4 or 5 args");
}
Vec2i pos1;
Vec2i pos2;
CclGetPos(l, &pos1.x, &pos1.y, 1);
CclGetPos(l, &pos2.x, &pos2.y, 2);
if (pos1.x > pos2.x) {
std::swap(pos1.x, pos2.x);
}
if (pos1.y > pos2.y) {
std::swap(pos1.y, pos2.y);
}
const int oldp = LuaToNumber(l, 3);
const int newp = LuaToNumber(l, 4);
std::vector<CUnit *> table;
// Change all units
if (args == 4) {
Select(pos1, pos2, table, HasSamePlayerAs(Players[oldp]));
} else { //Change only specific units by the type.
CUnitType *type = UnitTypeByIdent(LuaToString(l, 5));
Select(pos1, pos2, table, HasSamePlayerAndTypeAs(Players[oldp], *type));
}
for (auto unit : table) {
unit->ChangeOwner(Players[newp]);
}
return 0;
}
Description
GiveUnitsToPlayer(amount, type, fromPlayer, toPlayer)
GiveUnitsToPlayer(amount, type, topLeft, bottomRight, fromPlayer, toPlayer)
Give some units of a specific type from a player to another player. Optionally only inside a rectangle.
Returns number of units actually assigned. This can be smaller than the requested amount if the
fromPlayer
did not have enough units.
Instead of a number you can pass "all" as the first argument, to hand over all units.
Instead of a unit type name, you can pass "any", "unit", "building" as the second argument,
to hand over anything, and unit, or any building.
@param l Lua state.
Example:
-- Give 2 peasants from player 4 to player 2
GiveUnitsToPlayer(2, "unit-peasant", 4, 2)
-- Give 4 knights from player 5 to player 1 inside the rectangle 2,2 - 14,14
GiveUnitsToPlayer(2, "unit-peasant", {2,2}, {14,14}, 4, 2)
-- Give any 4 units from player 5 to player 1 inside the rectangle 2,2 - 14,14
GiveUnitsToPlayer(2, "any", 4, 2)
static int CclGiveUnitsToPlayer(lua_State *l)
{
int args = lua_gettop(l);
if (args != 4 && args != 6) {
LuaError(l, "incorrect argument count for GiveUnitsToPlayer, need 4 or 6 args");
}
int cnt;
if (lua_isnumber(l, 1)) {
cnt = LuaToNumber(l, 1);
} else {
std::string cntStr = std::string(LuaToString(l, 1));
if (cntStr != "all") {
LuaError(l, "incorrect 1st argument to GiveUnitsToPlayer. Must be number or 'all'");
}
cnt = std::numeric_limits<int>::max();
}
const int oldp = LuaToNumber(l, args == 4 ? 3 : 5);
const int newp = LuaToNumber(l, args == 4 ? 4 : 6);
std::string typestr = std::string(LuaToString(l, 2));
int assignedCnt = 0;
CUnitType *type = nullptr;
bool any = false;
bool onlyUnits = false;
bool onlyBuildings = false;
if ((any = (typestr == "any"))) {
} else if ((onlyUnits = (typestr == "unit"))) {
} else if ((onlyBuildings = (typestr == "building"))) {
} else {
type = UnitTypeByIdent(LuaToString(l, 2));
if (!type) {
LuaError(l, "incorrect 2nd argument to GiveUnitsToPlayer. Must be a unit type or 'any', 'unit', or 'building'");
}
}
if (cnt > 0) {
std::vector<CUnit *> table;
if (args == 6) {
Vec2i pos1;
Vec2i pos2;
CclGetPos(l, &pos1.x, &pos1.y, 3);
CclGetPos(l, &pos2.x, &pos2.y, 4);
if (pos1.x > pos2.x) {
std::swap(pos1.x, pos2.x);
}
if (pos1.y > pos2.y) {
std::swap(pos1.y, pos2.y);
}
if (any) {
Select(pos1, pos2, table, HasSamePlayerAs(Players[oldp]));
} else if (onlyUnits) {
Select(pos1, pos2, table, AndPredicate(HasSamePlayerAs(Players[oldp]), NotPredicate(IsBuildingType())));
} else if (onlyBuildings) {
Select(pos1, pos2, table, AndPredicate(HasSamePlayerAs(Players[oldp]), IsBuildingType()));
} else {
Select(pos1, pos2, table, HasSamePlayerAndTypeAs(Players[oldp], *type));
}
for (size_t i = 0; i != table.size() && cnt > 0; ++i) {
table[i]->ChangeOwner(Players[newp]);
assignedCnt++;
cnt--;
}
} else {
std::vector<CUnit *> table;
for (std::vector<CUnit *>::const_iterator it = Players[oldp].UnitBegin(); it != Players[oldp].UnitEnd() && cnt > 0; ++it) {
CUnit *unit = *it;
if (any || (onlyUnits && !unit->Type->Building) || (onlyBuildings && unit->Type->Building) || (type == unit->Type)) {
table.push_back(unit);
}
}
for (auto unit : table) {
unit->ChangeOwner(Players[newp]);
}
assignedCnt = table.size();
}
}
lua_pushnumber(l, assignedCnt);
return 1;
}
Description
Get ThisPlayer.
@param l Lua state.
Example:
GetThisPlayer()
static int CclGetThisPlayer(lua_State *l)
{
LuaCheckArgs(l, 0);
if (ThisPlayer) {
lua_pushnumber(l, ThisPlayer - Players);
} else {
lua_pushnumber(l, 0);
}
return 1;
}
Description
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;
}
Description
Set the maximum amount of units that can be selected.
@param l Lua state.
Example:
-- 9 units can be selected together.
SetMaxSelectable(9)
-- 18 units can be selected together.
SetMaxSelectable(18)
-- 50 units can be selected together.
SetMaxSelectable(50)
static int CclSetMaxSelectable(lua_State *l)
{
LuaCheckArgs(l, 1);
MaxSelectable = LuaToNumber(l, 1);
lua_pushnumber(l, MaxSelectable);
return 1;
}
Description
Set players units limit.
@param l Lua state.
Example:
SetAllPlayersUnitLimit(200)
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;
}
Description
Set players buildings limit.
@param l Lua state.
Example:
SetAllPlayersBuildingLimit(200)
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;
}
Description
Set players total units limit.
@param l Lua state.
Example:
SetAllPlayersTotalUnitLimit(400)
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;
}
Description
Change the diplomacy from player to another player.
@param l Lua state.
@return FIXME: should return old state.
Example:
SetDiplomacy(0,"allied",1)
SetDiplomacy(1,"allied",0)
SetDiplomacy(0,"enemy",2)
SetDiplomacy(1,"enemy",2)
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;
}
Get diplomacy from one player to another. Returns the strings "allied",
"enemy", "neutral", or "crazy".
static int CclGetDiplomacy(lua_State *l)
{
LuaCheckArgs(l, 2);
const int base = LuaToNumber(l, 1);
const int plynr = LuaToNumber(l, 2);
if (Players[base].IsEnemy(plynr)) {
if (Players[base].IsAllied(plynr)) {
lua_pushstring(l, "crazy");
} else {
lua_pushstring(l, "enemy");
}
} else if (Players[base].IsAllied(plynr)) {
lua_pushstring(l, "allied");
} else {
lua_pushstring(l, "neutral");
}
return 1;
}
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);
}
Description
Change the shared vision from player to another player.
@param l Lua state.
@return FIXME: should return old state.
Example:
SetSharedVision(0,true,1)
SetSharedVision(1,true,0)
SetSharedVision(0,false,2)
SetSharedVision(1,false,2)
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);
}
Description
Change the players revelation type - reveal all units, only buidings or don't reveal anything
@param l Lua state.
Example:
SetRevelationType("no-revelation")
SetRevelationType("buildings-only")
SetRevelationType("all-units")
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);
}
Description
Define player colors. Pass "false" as an optional second
argument to add the colors to the existing ones.
@param l Lua state.
Example:
DefinePlayerColors({
"red", {{164, 0, 0}, {124, 0, 0}, {92, 4, 0}, {68, 4, 0}},
"blue", {{12, 72, 204}, {4, 40, 160}, {0, 20, 116}, {0, 4, 76}},
"green", {{44, 180, 148}, {20, 132, 92}, {4, 84, 44}, {0, 40, 12}},
"violet", {{152, 72, 176}, {116, 44, 132}, {80, 24, 88}, {44, 8, 44}},
"orange", {{248, 140, 20}, {200, 96, 16}, {152, 60, 16}, {108, 32, 12}},
"black", {{40, 40, 60}, {28, 28, 44}, {20, 20, 32}, {12, 12, 20}},
"white", {{224, 224, 224}, {152, 152, 180}, {84, 84, 128}, {36, 40, 76}},
"yellow", {{252, 252, 72}, {228, 204, 40}, {204, 160, 16}, {180, 116, 0}},
"red", {{164, 0, 0}, {124, 0, 0}, {92, 4, 0}, {68, 4, 0}},
"blue", {{12, 72, 204}, {4, 40, 160}, {0, 20, 116}, {0, 4, 76}},
"green", {{44, 180, 148}, {20, 132, 92}, {4, 84, 44}, {0, 40, 12}},
"violet", {{152, 72, 176}, {116, 44, 132}, {80, 24, 88}, {44, 8, 44}},
"orange", {{248, 140, 20}, {200, 96, 16}, {152, 60, 16}, {108, 32, 12}},
"black", {{40, 40, 60}, {28, 28, 44}, {20, 20, 32}, {12, 12, 20}},
"white", {{224, 224, 224}, {152, 152, 180}, {84, 84, 128}, {36, 40, 76}},
"yellow", {{252, 252, 72}, {228, 204, 40}, {204, 160, 16}, {180, 116, 0}},
})
static int CclDefinePlayerColors(lua_State *l)
{
int nargs = lua_gettop(l);
if (nargs < 1 || nargs > 2) {
LuaError(l, "wrong number of arguments");
}
if (!lua_istable(l, 1)) {
LuaError(l, "incorrect argument");
}
bool defaultNeutralPlayer = false;
const int args = lua_rawlen(l, 1);
if (nargs < 2 || LuaToBoolean(l, 2)) {
PlayerColorNames.clear();
PlayerColorsRGB.clear();
PlayerColorsSDL.clear();
if (args / 2 < PlayerMax - 1) { // accept no color for neutral player
LuaError(l, "You need to define at least %d colors" _C_ PlayerMax - 1);
}
if (args / 2 < PlayerMax) {
defaultNeutralPlayer = true;
}
}
for (int i = 0; i < args; ++i) {
PlayerColorNames.push_back(LuaToString(l, 1, i + 1));
++i;
lua_rawgeti(l, 1, i + 1);
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument");
}
const int numcolors = lua_rawlen(l, -1);
if (numcolors != PlayerColorIndexCount) {
LuaError(l, "You should use %d colors (See DefinePlayerColorIndex())" _C_ PlayerColorIndexCount);
}
std::vector<CColor> newColors;
for (int j = 0; j < numcolors; ++j) {
lua_rawgeti(l, -1, j + 1);
CColor newColor;
newColor.Parse(l);
newColors.push_back(newColor);
lua_pop(l, 1);
}
PlayerColorsRGB.push_back(newColors);
PlayerColorsSDL.push_back(std::vector<SDL_Color>(newColors.begin(), newColors.end()));
}
if (defaultNeutralPlayer) {
PlayerColorNames.push_back("neutral-black");
std::vector<CColor> neutralColors;
for (int j = 0; j < PlayerColorIndexCount; ++j) {
CColor neutralColor;
neutralColors.push_back(neutralColor);
}
PlayerColorsRGB.push_back(neutralColors);
PlayerColorsSDL.push_back(std::vector<SDL_Color>(neutralColors.begin(), neutralColors.end()));
}
return 0;
}
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);
PlayerColorsRGB.clear();
PlayerColorsSDL.clear();
return 0;
}
Make new player colors
@param l Lua state.
static int CclNewPlayerColors(lua_State *l)
{
LuaCheckArgs(l, 0);
SetPlayersPalette();
return 0;
}
Description
Get player data.
@param l Lua state.
Example:
GetPlayerData(0,"TotalNumUnits")
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;
}
Description
Set player data.
@param l Lua state.
Example:
SetPlayerData(0,"Name","Nation of Stromgarde") -- set the name of this player
SetPlayerData(0,"RaceName","human") -- the the race to human
SetPlayerData(0,"Resources","gold",1700) -- set the player to have 1700 gold
SetPlayerData(0, "Allow", "upgrade-paladin", "R") -- give the player the Paladin upgrade
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;
}
Description
Set ai player algo.
@param l Lua state.
Example:
-- Player 1 has a passive A.I
SetAiType(1, "Passive")
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;
}
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;
}
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;
}
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.
Example:
u_data = UnitType("unit-footman")
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);
}
/stratagus/script.cpp:2701 CclListFilesystem
static int CclListFilesystem(lua_State *l)
{
LuaCheckArgs(l, 1);
const char *dir = LuaToString(l, 1);
#ifdef WIN32
if (strcmp(dir, "/") == 0) {
std::vector<fs::path> vols = getVolumes();
lua_newtable(l);
int j = 0;
for (auto const& vol: vols) {
if (!access(vol.generic_u8string().c_str(), R_OK)) {
lua_pushnumber(l, ++j);
lua_pushstring(l, vol.generic_u8string().c_str());
lua_settable(l, -3);
}
}
return 1;
}
#endif
lua_newtable(l);
int j = 0;
for (auto const& dir_entry: fs::directory_iterator(fs::path(dir))) {
if ((fs::is_regular_file(dir_entry.path()) || fs::is_directory(dir_entry.path())) && !access(dir_entry.path().generic_u8string().c_str(), R_OK)) {
std::string name = dir_entry.path().generic_u8string();
if (fs::is_directory(dir_entry.path())) {
name += "/";
}
lua_pushnumber(l, ++j);
lua_pushstring(l, name.c_str());
lua_settable(l, -3);
}
}
return 1;
}
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)
{
const int arg = lua_gettop(l);
if (arg < 1 || arg > 2) {
LuaError(l, "incorrect argument");
}
const std::string filename = LibraryFileName(LuaToString(l, 1));
bool exitOnError = arg == 2 ? LuaToBoolean(l, 2) : true;
if (LuaLoadFile(filename, "", exitOnError) == -1) {
DebugPrint("Load failed: %s\n" _C_ filename.c_str());
}
return 0;
}
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\n", ar.source, ar.currentline, ar.what, LuaToString(l, 1));
#endif
return 1;
}
Restart the entire game. This function only returns when an error happens.
static int CclRestartStratagus(lua_State *l)
{
LuaCheckArgs(l, 0);
#ifdef WIN32
char executable_path[MAX_PATH];
memset(executable_path, 0, sizeof(executable_path));
GetModuleFileName(NULL, executable_path, sizeof(executable_path)-1);
#else
char *executable_path = const_cast<char*>(OriginalArgv[0].c_str());
#endif
bool insertRestartArgument = true;
for (auto arg : OriginalArgv) {
if (arg == "-r") {
insertRestartArgument = false;
break;
}
}
std::vector<std::string> quotedArgs = QuoteArguments(OriginalArgv);
int newArgc = quotedArgs.size() + (insertRestartArgument ? 2 : 1);
char **argv = new char*[newArgc];
for (unsigned int i = 0; i < quotedArgs.size(); i++) {
argv[i] = const_cast<char*>(quotedArgs[i].c_str());
}
if (insertRestartArgument) {
argv[newArgc - 2] = (char*)"-r";
}
argv[newArgc - 1] = (char *)0;
#ifdef WIN32
_execv(executable_path, argv);
#else
execvp(executable_path, argv);
#endif
delete[] argv;
return 0;
}
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 if (!strcmp(value, "max-search-iterations")) {
++j;
i = LuaToNumber(l, j + 1);
if (i <= 0) {
PrintFunction();
fprintf(stdout, "Max A* search iterations must be strictly > 0\n");
} else {
AStarMaxSearchIterations = i;
}
} else {
LuaError(l, "Unsupported tag: %s" _C_ value);
}
}
return 0;
}
Description
Return of game name.
@param l Lua state.
Example:
SetGameName("Wargus Map - Chapter 1")
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:1164 CclSetFullGameName
static int CclSetFullGameName(lua_State *l)
{
const int args = lua_gettop(l);
if (args > 1 || (args == 1 && (!lua_isnil(l, 1) && !lua_isstring(l, 1)))) {
LuaError(l, "incorrect argument");
}
if (args == 1 && !lua_isnil(l, 1)) {
FullGameName = lua_tostring(l, 1);
}
return 0;
}
Description
Set God mode.
@param l Lua state.
@return The old mode.
Example:
-- God Mode enabled
SetGodMode(true)
-- God Mode disabled
SetGodMode(false)
static int CclSetGodMode(lua_State *l)
{
LuaCheckArgs(l, 1);
GodMode = LuaToBoolean(l, 1);
return 0;
}
Description
Get God mode.
@param l Lua state.
@return God mode.
Example:
g_mode = GetGodMode()
print(g_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;
}
Description
Set the local player name
@param l Lua state.
Example:
SetLocalPlayerName("Stormreaver Clan")
static int CclSetLocalPlayerName(lua_State *l)
{
LuaCheckArgs(l, 1);
Parameters::Instance.LocalPlayerName = LuaToString(l, 1);
return 0;
}
Description
Get the local player name
@param l Lua state.
Example:
GetLocalPlayerName()
static int CclGetLocalPlayerName(lua_State *l)
{
LuaCheckArgs(l, 0);
lua_pushstring(l, Parameters::Instance.LocalPlayerName.c_str());
return 1;
}
/game/game.cpp:1528 CclSetMenuRace
static int CclSetMenuRace(lua_State *l)
{
LuaCheckArgs(l, 1);
MenuRace = LuaToString(l, 1);
return 0;
}
Description
Get Stratagus Version
Example:
version = GetStratagusVersion()
print(version)
static int CclGetStratagusVersion(lua_State *l)
{
LuaCheckArgs(l, 0);
lua_pushstring(l, VERSION);
return 1;
}
Description
Get Stratagus Homepage
Example:
url = GetStratagusHomepage()
print(url)
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;
}
Description
Add a trigger.
Example:
AddTrigger(
function() return (GetPlayerData(1,"UnitTypesCount","unit-farm") >= 4) end,
function() return ActionVictory() end
)
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;
}
Description
Return the number of units of a given unit-type and player at a location.
Example:
-- Get the number of knights from player 1 from position 0,0 to 20,15
num_units = GetNumUnitsAt(1,"unit-knight",{0,0},{20,15})
print(num_units)
static int CclGetNumUnitsAt(lua_State *l)
{
LuaCheckArgs(l, 4);
int plynr = LuaToNumber(l, 1);
lua_pushvalue(l, 2);
const CUnitType *unittype = TriggerGetUnitType(l);
lua_pop(l, 1);
Vec2i minPos;
Vec2i maxPos;
CclGetPos(l, &minPos.x, &minPos.y, 3);
CclGetPos(l, &maxPos.x, &maxPos.y, 4);
if (minPos.x > maxPos.x) {
std::swap(minPos.x, maxPos.x);
}
if (minPos.y > maxPos.y) {
std::swap(minPos.y, maxPos.y);
}
std::vector<CUnit *> units;
Select(minPos, maxPos, units);
int s = 0;
for (size_t i = 0; i != units.size(); ++i) {
const CUnit &unit = *units[i];
// Check unit type
if (unittype == ANY_UNIT
|| (unittype == ALL_FOODUNITS && !unit.Type->Building)
|| (unittype == ALL_BUILDINGS && unit.Type->Building)
|| (unittype == unit.Type && !unit.Constructed)) {
// Check the player
if (plynr == -1 || plynr == unit.Player->Index) {
if (unit.IsAlive()) {
++s;
}
}
}
}
lua_pushnumber(l, s);
return 1;
}
Description
Player has the quantity of unit-type near to unit-type.
Example:
AddTrigger(
function() return IfNearUnit(0,">",1,"unit-peasant","unit-town-hall") end,
function()
AddMessage("Player 0 has more than 1 peasant near the Town Hall")
return false end
)
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;
}
Description
Player has the quantity of rescued unit-type near to unit-type.
Example:
IfRescuedNearUnit("this", ">=", 1, "unit-archer", "unit-circle-of-power")
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 = lua_tointeger(l, -1);
} else {
LuaError(l, "Unsupported key: %s" _C_ value);
}
lua_pop(l, 1);
}
// Append to linked list
last = &CurrentReplay->Commands;
while (*last) {
last = &(*last)->Next;
}
*last = log;
return 0;
}
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, "LocalPlayer")) {
replay->LocalPlayer = LuaToNumber(l, -1);
} else if (!strcmp(value, "Players")) {
if (!lua_istable(l, -1) || lua_rawlen(l, -1) != PlayerMax) {
LuaError(l, "incorrect argument");
}
for (j = 0; j < PlayerMax; ++j) {
int top;
lua_rawgeti(l, -1, j + 1);
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument");
}
top = lua_gettop(l);
lua_pushnil(l);
while (lua_next(l, top) != 0) {
value = LuaToString(l, -2);
if (!strcmp(value, "Name")) {
replay->PlayerNames[j] = LuaToString(l, -1);
} else if (!strcmp(value, "AIScript")) {
replay->ReplaySettings.Presets[j].AIScript = LuaToString(l, -1);
} else if (!strcmp(value, "PlayerColor")) {
replay->ReplaySettings.Presets[j].PlayerColor = LuaToNumber(l, -1);
} else if (!strcmp(value, "Race")) {
replay->ReplaySettings.Presets[j].Race = LuaToNumber(l, -1);
} else if (!strcmp(value, "Team")) {
replay->ReplaySettings.Presets[j].Team = LuaToNumber(l, -1);
} else if (!strcmp(value, "Type")) {
replay->ReplaySettings.Presets[j].Type = static_cast<PlayerTypes>(LuaToNumber(l, -1));
} else {
LuaError(l, "Unsupported key: %s" _C_ value);
}
lua_pop(l, 1);
}
lua_pop(l, 1);
}
} else if (!strcmp(value, "Engine")) {
if (!lua_istable(l, -1) || lua_rawlen(l, -1) != 3) {
LuaError(l, "incorrect argument");
}
replay->Engine[0] = LuaToNumber(l, -1, 1);
replay->Engine[1] = LuaToNumber(l, -1, 2);
replay->Engine[2] = LuaToNumber(l, -1, 3);
} else if (!strcmp(value, "Network")) {
if (!lua_istable(l, -1) || lua_rawlen(l, -1) != 3) {
LuaError(l, "incorrect argument");
}
replay->Network[0] = LuaToNumber(l, -1, 1);
replay->Network[1] = LuaToNumber(l, -1, 2);
replay->Network[2] = LuaToNumber(l, -1, 3);
} else {
if (!replay->ReplaySettings.SetField(value, LuaToNumber(l, -1))) {
LuaError(l, "Unsupported key: %s" _C_ value);
}
}
lua_pop(l, 1);
}
CurrentReplay = replay;
// Apply CurrentReplay settings.
if (!SaveGameLoading) {
ApplyReplaySettings();
} else {
CommandLogDisabled = false;
}
return 0;
}
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;
}
Description
Define an AI engine.
@param l Lua state.
@return FIXME: docu
Example:
-- Those instructions will be executed forever
local simple_ai_loop = {
-- Sleep for 5 in game minutes
function() return AiSleep(9000) end,
-- Repeat the functions from start.
function() stratagus.gameData.AIState.loop_index[1 + AiPlayer()] = 0; return false; end,
}
-- The initial instructions the A.I has to execute
local simple_ai = {
function() return AiSleep(1800) end, -- Sleep for 1 in game minute
function() return AiNeed("unit-town-hall") end, -- One Town Hall is needed
function() return AiWait("unit-town-hall") end, -- Wait until the Town Hall is completed
function() return AiSet("unit-peasant", 4) end, -- Make 4 peasants
-- Basic buildings
function() return AiSet("unit-farm", 4) end, -- Make 4 farms
function() return AiWait("unit-farm") end, -- Wait until all 4 farms are build.
function() return AiNeed("unit-human-barracks") end, -- Need a Barracks
function() return AiWait("unit-human-barracks") end, -- Wait until the Barracks has been built
-- Defense force for the base
function() return AiForce(1, {"unit-footman", 3}) end, -- Make a force of 3 footmen
function() return AiWaitForce(1) end, -- Wait until the 3 footmen are trained
function() return AiForceRole(1,"defend") end, -- Make this force as a defense force
-- Execute the instructions in simple_ai_loop
function() return AiLoop(simple_ai_loop, stratagus.gameData.AIState.loop_index) end,
}
-- function that calls the instructions in simple_ai inside DefineAi
function custom_ai() return AiLoop(simple_ai,stratagus.gameData.AIState.index) end
-- Make an A.I for the human race that calls the function custom_ai
DefineAi("example_ai","human","class_ai",custom_ai)
static int CclDefineAi(lua_State *l)
{
LuaCheckArgs(l, 4);
if (!lua_isfunction(l, 4)) {
LuaError(l, "incorrect argument");
}
CAiType *aitype = new CAiType;
// AI Name
const char *aiName = LuaToString(l, 1);
aitype->Name = aiName;
#ifdef DEBUG
if (GetAiTypesByName(aiName)) {
DebugPrint("Warning two or more AI's with the same name '%s'\n" _C_ aiName);
}
#endif
AiTypes.insert(AiTypes.begin(), aitype);
// AI Race
const char *value = LuaToString(l, 2);
if (*value != '*') {
aitype->Race = value;
} else {
aitype->Race.clear();
}
// AI Class
aitype->Class = LuaToString(l, 3);
// AI Script
lua_getglobal(l, "_ai_scripts_");
if (lua_isnil(l, -1)) {
lua_pop(l, 1);
lua_newtable(l);
lua_setglobal(l, "_ai_scripts_");
lua_getglobal(l, "_ai_scripts_");
}
aitype->Script = aitype->Name + aitype->Race + aitype->Class;
lua_pushstring(l, aitype->Script.c_str());
lua_pushvalue(l, 4);
lua_rawset(l, 5);
lua_pop(l, 1);
return 0;
}
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;
}
Description
Get the number of cycles to sleep.
@param l Lua state
@return Number of return values
Example:
local simple_ai_loop = {
-- Sleep for 5 in game minutes
function() return AiSleep(9000) end,
-- Repeat the instructions forever.
function() stratagus.gameData.AIState.loop_index[1 + AiPlayer()] = 0; return false; end,
}
local simple_ai = {
-- Get the number of cycles to sleep.
function() return AiSleep(AiGetSleepCycles()) end,
-- Execute the instructions in simple_ai_loop
function() return AiLoop(simple_ai_loop, stratagus.gameData.AIState.loop_index) end,
}
function custom_ai() return AiLoop(simple_ai,stratagus.gameData.AIState.index) end
DefineAi("example_ai","human","class_ai",custom_ai)
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;
}
Description
Need a unit.
@param l Lua state.
@return Number of return values
Example:
local simple_ai_loop = {
-- Sleep for 5 in game minutes
function() return AiSleep(9000) end,
-- Repeat the instructions forever.
function() stratagus.gameData.AIState.loop_index[1 + AiPlayer()] = 0; return false; end,
}
local simple_ai = {
function() return AiSleep(AiGetSleepCycles()) end,
-- Tell to the A.I that it needs a Town Hall.
function() return AiNeed("unit-town-hall") end,
-- Execute the instructions in simple_ai_loop
function() return AiLoop(simple_ai_loop, stratagus.gameData.AIState.loop_index) end,
}
function custom_ai() return AiLoop(simple_ai,stratagus.gameData.AIState.index) end
DefineAi("example_ai","human","class_ai",custom_ai)
static int CclAiNeed(lua_State *l)
{
LuaCheckArgs(l, 1);
InsertUnitTypeRequests(CclGetUnitType(l), 1);
lua_pushboolean(l, 0);
return 1;
}
Description
Set the number of units.
@param l Lua state
@return Number of return values
Example:
local simple_ai_loop = {
-- Sleep for 5 in game minutes
function() return AiSleep(9000) end,
-- Repeat the instructions forever.
function() stratagus.gameData.AIState.loop_index[1 + AiPlayer()] = 0; return false; end,
}
local simple_ai = {
function() return AiSleep(AiGetSleepCycles()) end,
-- Tell to the A.I that it needs a Town Hall.
function() return AiNeed("unit-town-hall") end,
-- Wait until the town-hall has been built.
function() return AiWait("unit-town-hall") end,
-- Tell to the A.I that it needs 4 peasants
function() return AiSet("unit-peasant",4) end,
-- Execute the instructions in simple_ai_loop
function() return AiLoop(simple_ai_loop, stratagus.gameData.AIState.loop_index) end,
}
function custom_ai() return AiLoop(simple_ai,stratagus.gameData.AIState.index) end
DefineAi("example_ai","human","class_ai",custom_ai)
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;
}
Description
Wait for a unit.
@param l Lua State.
@return Number of return values
Example:
local simple_ai_loop = {
-- Sleep for 5 in game minutes
function() return AiSleep(9000) end,
-- Repeat the instructions forever.
function() stratagus.gameData.AIState.loop_index[1 + AiPlayer()] = 0; return false; end,
}
local simple_ai = {
function() return AiSleep(AiGetSleepCycles()) end,
-- Tell to the A.I that it needs a Town Hall.
function() return AiNeed("unit-town-hall") end,
-- Wait until the Town Hall has been built.
function() return AiWait("unit-town-hall") end,
-- Execute the instructions in simple_ai_loop
function() return AiLoop(simple_ai_loop, stratagus.gameData.AIState.loop_index) end,
}
function custom_ai() return AiLoop(simple_ai,stratagus.gameData.AIState.index) end
DefineAi("example_ai","human","class_ai",custom_ai)
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;
}
Description
Define a force, a groups of units.
@param l Lua state.
Example:
local simple_ai_loop = {
-- Sleep for 5 in game minutes
function() return AiSleep(9000) end,
-- Repeat the instructions forever.
function() stratagus.gameData.AIState.loop_index[1 + AiPlayer()] = 0; return false; end,
}
local simple_ai = {
function() return AiSleep(AiGetSleepCycles()) end,
-- Tell to the A.I that it needs a Town Hall.
function() return AiNeed("unit-town-hall") end,
-- Wait until the Town Hall has been built.
function() return AiWait("unit-town-hall") end,
-- Tell to the A.I that it needs 4 peasants
function() return AiSet("unit-peasant",4) end,
-- Tell to the A.I that it needs a Barracks.
function() return AiNeed("unit-human-barracks") end,
-- Tell to the A.I that it needs a Lumbermill.
function() return AiNeed("unit-elven-lumber-mill") end,
-- Wait until the Barracks has been built.
function() return AiWait("unit-human-barracks") end,
-- Wait until the Lumbermill has been built.
function() return AiWait("unit-elven-lumber-mill") end,
-- Specify the force number 1 made only of 3 footmen
function() return AiForce(1,{"unit-footman", 3}) end,
-- Specify the force number 2 made only of 2 archers
function() return AiForce(2,{"unit-archer", 2}) end,
-- Specify the force number 3 made of 2 footmen and 1 archer
function() return AiForce(3,{"unit-footman", 2, "unit-archer", 1}) end,
-- Wait for all three forces
function() return AiWaitForce(1) end,
function() return AiWaitForce(2) end,
function() return AiWaitForce(3) end,
-- Execute the instructions in simple_ai_loop
function() return AiLoop(simple_ai_loop, stratagus.gameData.AIState.loop_index) end,
}
function custom_ai() return AiLoop(simple_ai,stratagus.gameData.AIState.index) end
DefineAi("example_ai","human","class_ai",custom_ai)
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;
}
Description
Define the role of a force.
@param l Lua state.
Example:
local simple_ai_loop = {
function() return AiSleep(9000) end,
function() stratagus.gameData.AIState.loop_index[1 + AiPlayer()] = 0; return false; end,
}
local simple_ai = {
function() return AiSleep(AiGetSleepCycles()) end,
function() return AiNeed("unit-town-hall") end,
function() return AiWait("unit-town-hall") end,
function() return AiSet("unit-peasant",4) end,
function() return AiNeed("unit-human-barracks") end,
function() return AiNeed("unit-elven-lumber-mill") end,
-- Force 1 has the role of attacker
function() return AiForceRole(1,"attack") end,
-- Force 2 has the role of defender
function() return AiForceRole(2,"defend") end,
function() return AiForce(1,{"unit-footman", 3}) end,
function() return AiForce(2,{"unit-archer", 2}) end,
function() return AiWaitForce(1) end,
function() return AiWaitForce(2) end,
-- Execute the instructions in simple_ai_loop
function() return AiLoop(simple_ai_loop, stratagus.gameData.AIState.loop_index) end,
}
function custom_ai() return AiLoop(simple_ai,stratagus.gameData.AIState.index) end
DefineAi("example_ai","human","class_ai",custom_ai)
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;
}
Description
Wait for a force ready.
@param l Lua state.
Example:
local simple_ai_loop = {
function() return AiSleep(9000) end,
function() stratagus.gameData.AIState.loop_index[1 + AiPlayer()] = 0; return false; end,
}
local simple_ai = {
function() return AiSleep(AiGetSleepCycles()) end,
function() return AiNeed("unit-town-hall") end,
function() return AiWait("unit-town-hall") end,
function() return AiSet("unit-peasant",4) end,
function() return AiNeed("unit-human-barracks") end,
function() return AiWait("unit-human-barracks") end,
function() return AiForce(1,{"unit-footman", 3}) end,
-- Wait until force 1 is completed
function() return AiWaitForce(1) end,
function() return AiLoop(simple_ai_loop, stratagus.gameData.AIState.loop_index) end,
}
function custom_ai() return AiLoop(simple_ai,stratagus.gameData.AIState.index) end
DefineAi("example_ai","human","class_ai",custom_ai)
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;
}
Description
Attack with one single force.
@param l Lua state.
Example:
local simple_ai_loop = {
function() return AiSleep(9000) end,
function() stratagus.gameData.AIState.loop_index[1 + AiPlayer()] = 0; return false; end,
}
local simple_ai = {
function() return AiSleep(AiGetSleepCycles()) end,
function() return AiNeed("unit-town-hall") end,
function() return AiWait("unit-town-hall") end,
function() return AiSet("unit-peasant",4) end,
function() return AiNeed("unit-human-barracks") end,
function() return AiWait("unit-human-barracks") end,
function() return AiForce(1,{"unit-footman", 3}) end,
function() return AiWaitForce(1) end,
-- Attack with Force 1
function() return AiAttackWithForce(1) end,
function() return AiForce(2,{"unit-footman",5}) end,
function() return AiWaitForce(2) end,
-- Attack with Force 2
function() return AiAttackWithForce(2) end,
function() return AiLoop(simple_ai_loop, stratagus.gameData.AIState.loop_index) end,
}
function custom_ai() return AiLoop(simple_ai,stratagus.gameData.AIState.index) end
DefineAi("example_ai","human","class_ai",custom_ai)
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;
}
Description
Sleep for n cycles.
@param l Lua state.
Example:
local simple_ai_loop = {
-- Sleep for 5 in game minutes
function() return AiSleep(9000) end,
function() stratagus.gameData.AIState.loop_index[1 + AiPlayer()] = 0; return false; end,
}
local simple_ai = {
-- Get the number of cycles to sleep
function() return AiSleep(AiGetSleepCycles()) end,
function() return AiNeed("unit-town-hall") end,
function() return AiWait("unit-town-hall") end,
function() return AiSet("unit-peasant",4) end,
-- Sleep for 1 in game minute
function() return AiSleep(1800) end,
function() return AiNeed("unit-human-blacksmith") end,
function() return AiWait("unit-human-blacksmith") end,
function() return AiLoop(simple_ai_loop, stratagus.gameData.AIState.loop_index) end,
}
function custom_ai() return AiLoop(simple_ai,stratagus.gameData.AIState.index) end
DefineAi("example_ai","human","class_ai",custom_ai)
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;
}
Description
Research an upgrade.
@param l Lua state.
Example:
local simple_ai_loop = {
function() return AiSleep(9000) end,
function() stratagus.gameData.AIState.loop_index[1 + AiPlayer()] = 0; return false; end,
}
local simple_ai = {
-- Get the number of cycles to sleep
function() return AiSleep(AiGetSleepCycles()) end,
function() return AiNeed("unit-town-hall") end,
function() return AiWait("unit-town-hall") end,
function() return AiSet("unit-peasant",4) end,
function() return AiNeed("unit-human-barracks") end,
function() return AiWait("unit-human-barracks") end,
function() return AiNeed("unit-elven-lumber-mill") end,
function() return AiWait("unit-elven-lumber-mill") end,
function() return AiForce(1,{"unit-footman", 1, "unit-archer", 2}) end,
function() return AiWaitForce(1) end,
-- Upgrade the archers arrow.
function() return AiResearch("upgrade-arrow1") end,
function() return AiLoop(simple_ai_loop, stratagus.gameData.AIState.loop_index) end,
}
function custom_ai() return AiLoop(simple_ai,stratagus.gameData.AIState.index) end
DefineAi("example_ai","human","class_ai",custom_ai)
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;
}
Description
Upgrade an unit to an new unit-type.
@param l Lua state.
Example:
local simple_ai_loop = {
function() return AiSleep(9000) end,
function() stratagus.gameData.AIState.loop_index[1 + AiPlayer()] = 0; return false; end,
}
local simple_ai = {
function() return AiSleep(AiGetSleepCycles()) end,
function() return AiNeed("unit-town-hall") end,
function() return AiWait("unit-town-hall") end,
function() return AiSet("unit-peasant",4) end,
function() return AiNeed("unit-human-barracks") end,
function() return AiWait("unit-human-barracks") end,
function() return AiNeed("unit-elven-lumber-mill") end,
function() return AiWait("unit-elven-lumber-mill") end,
function() return AiSleep(1800) end,
-- Upgrade the Town Hall to Keep
function() return AiUpgradeTo("unit-keep") end,
function() return AiWait("unit-keep") end,
function() return AiLoop(simple_ai_loop, stratagus.gameData.AIState.loop_index) end,
}
function custom_ai() return AiLoop(simple_ai,stratagus.gameData.AIState.index) end
DefineAi("example_ai","human","class_ai",custom_ai)
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;
}
Description
Set AI player resource collect percent.
@param l Lua state.
Example:
local simple_ai_loop = {
function() return AiSleep(9000) end,
function() stratagus.gameData.AIState.loop_index[1 + AiPlayer()] = 0; return false; end,
}
local simple_ai = {
function() return AiSleep(AiGetSleepCycles()) end,
function() return AiNeed("unit-town-hall") end,
function() return AiWait("unit-town-hall") end,
-- The peasants will focus only on gathering gold
function() return AiSetCollect({0,100,0,0,0,0,0}) end,
function() return AiSet("unit-peasant",4) end,
function() return AiWait("unit-peasant") end,
function() return AiSleep(1800) end,
-- The peasants will now focus 50% on gathering gold and 50% on gathering lumber
function() return AiSetCollect({0,50,50,0,0,0,0}) end,
function() return AiLoop(simple_ai_loop, stratagus.gameData.AIState.loop_index) end,
}
function custom_ai() return AiLoop(simple_ai,stratagus.gameData.AIState.index) end
DefineAi("example_ai","human","class_ai",custom_ai)
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;
}
Description
Dump some AI debug information.
@param l Lua state.
Example:
local simple_ai_loop = {
function() return AiSleep(3600) end,
-- Get the information from all the A.I players
function() return AiDump() end,
function() stratagus.gameData.AIState.loop_index[1 + AiPlayer()] = 0; return false; end,
}
local simple_ai = {
function() return AiSleep(AiGetSleepCycles()) end,
function() return AiNeed("unit-town-hall") end,
function() return AiWait("unit-town-hall") end,
function() return AiSet("unit-peasant",4) end,
function() return AiWait("unit-peasant") end,
function() return AiLoop(simple_ai_loop, stratagus.gameData.AIState.loop_index) end,
}
function custom_ai() return AiLoop(simple_ai,stratagus.gameData.AIState.index) end
DefineAi("example_ai","human","class_ai",custom_ai)
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;
}
Description
Attack with forces.
@param l Lua state.
Example:
local simple_ai_loop = {
function() return AiSleep(9000) end,
function() stratagus.gameData.AIState.loop_index[1 + AiPlayer()] = 0; return false; end,
}
local simple_ai = {
function() return AiSleep(AiGetSleepCycles()) end,
function() return AiNeed("unit-town-hall") end,
function() return AiWait("unit-town-hall") end,
function() return AiSet("unit-peasant",4) end,
function() return AiNeed("unit-human-barracks") end,
function() return AiWait("unit-human-barracks") end,
function() return AiNeed("unit-elven-lumber-mill") end,
function() return AiWait("unit-elven-lumber-mill") end,
function() return AiForce(1,{"unit-footman", 2}) end,
function() return AiForce(2,{"unit-archer",1}) end,
function() return AiForce(3,{"unit-archer",1,"unit-footman",3}) end,
-- Wait all three forces to be ready
function() return AiWaitForces({1,2,3}) end,
-- Attack with all three forces
function() return AiAttackWithForces({1,2,3}) end,
function() return AiLoop(simple_ai_loop, stratagus.gameData.AIState.loop_index) end,
}
function custom_ai() return AiLoop(simple_ai,stratagus.gameData.AIState.index) end
DefineAi("example_ai","human","class_ai",custom_ai)
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;
}
Description
Wait for a forces ready.
@param l Lua state.
Example:
local simple_ai_loop = {
function() return AiSleep(9000) end,
function() stratagus.gameData.AIState.loop_index[1 + AiPlayer()] = 0; return false; end,
}
local simple_ai = {
function() return AiSleep(AiGetSleepCycles()) end,
function() return AiNeed("unit-town-hall") end,
function() return AiWait("unit-town-hall") end,
function() return AiSet("unit-peasant",4) end,
function() return AiNeed("unit-human-barracks") end,
function() return AiWait("unit-human-barracks") end,
function() return AiNeed("unit-elven-lumber-mill") end,
function() return AiWait("unit-elven-lumber-mill") end,
function() return AiForce(1,{"unit-footman", 2}) end,
function() return AiForce(2,{"unit-archer",1}) end,
function() return AiForce(3,{"unit-archer",1,"unit-footman",3}) end,
-- Wait all three forces to be ready
function() return AiWaitForces({1,2,3}) end,
function() return AiLoop(simple_ai_loop, stratagus.gameData.AIState.loop_index) end,
}
function custom_ai() return AiLoop(simple_ai,stratagus.gameData.AIState.index) end
DefineAi("example_ai","human","class_ai",custom_ai)
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:1995 CclAiProcessorEnd
static int CclAiProcessorEnd(lua_State *l)
{
CTCPSocket *s = AiProcessorSendState(l, 'E');
s->Close();
delete s;
return 0;
}
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;
}
/editor/script_editor.cpp:93 CclEditorResizeMap
static int CclEditorResizeMap(lua_State *l)
{
LuaCheckArgs(l, 5);
int res = EditorSaveMapWithResize(LuaToString(l, 1),
{(short)LuaToNumber(l, 2), (short)LuaToNumber(l, 3)},
{(short)LuaToNumber(l, 4), (short)LuaToNumber(l, 5)});
lua_pushnumber(l, res);
return 1;
}
Confgure the randomize map feature of the editor.
@param l Lua state.
static int CclEditorRandomizeProperties(lua_State *l)
{
LuaCheckArgs(l, 1);
if (!lua_istable(l, 1)) {
LuaError(l, "incorrect argument");
}
Editor.RandomTiles.clear();
Editor.RandomUnits.clear();
for (lua_pushnil(l); lua_next(l, 1); lua_pop(l, 1)) {
const char *value = LuaToString(l, -2);
if (!strcmp(value, "BaseTile")) {
Editor.BaseTileIndex = LuaToNumber(l, -1);
} else if (!strcmp(value, "RandomTiles")) {
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument");
}
int subargs = lua_rawlen(l, -1);
for (int j = 0; j < subargs; j++) {
lua_rawgeti(l, -1, j + 1);
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument");
}
if (lua_rawlen(l, -1) != 3) {
LuaError(l, "incorrect RandomTiles entry length, need 3 integers");
}
Editor.RandomTiles.push_back(std::make_tuple(LuaToNumber(l, -1, 1), LuaToNumber(l, -1, 2), LuaToNumber(l, -1, 3)));
lua_pop(l, 1);
}
} else if (!strcmp(value, "RandomUnits")) {
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument");
}
int subargs = lua_rawlen(l, -1);
for (int j = 0; j < subargs; j++) {
lua_rawgeti(l, -1, j + 1);
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument");
}
if (lua_rawlen(l, -1) != 4) {
LuaError(l, "incorrect RandomUnits entry length, need 1 string followed by 3 integers");
}
Editor.RandomUnits.push_back(std::make_tuple(std::string(LuaToString(l, -1, 1)), LuaToNumber(l, -1, 2), LuaToNumber(l, -1, 3), LuaToNumber(l, -1, 4)));
lua_pop(l, 1);
}
}
}
return 0;
}
Controls Randomization of Player position in Multiplayer mode.
Without arguments, disables randomization. Otherwise, sets the
NoRandomization flag to the boolean argument value.
@param l Lua state.
static int CclNoRandomPlacementMultiplayer(lua_State *l)
{
int nargs = lua_gettop(l);
if (nargs > 1) {
LuaError(l, "incorrect argument");
}
bool flag = nargs ? LuaToBoolean(l, 1) : false;
NoRandomPlacementMultiplayer = flag;
return 0;
}
Return if player positions in multiplayer mode are randomized.
@param l Lua state.
static int CclUsesRandomPlacementMultiplayer(lua_State *l)
{
LuaCheckArgs(l, 0);
lua_pushboolean(l, !NoRandomPlacementMultiplayer);
return 1;
}
/network/netconnect.cpp:2092 CclNetworkDiscoverServers
static int CclNetworkDiscoverServers(lua_State *l)
{
LuaCheckArgs(l, 1);
bool start = LuaToBoolean(l, 1);
auto callback= [l](char* ip) {
auto i = lua_objlen(l, -1) + 1;
lua_pushnumber(l, i);
lua_pushstring(l, ip);
lua_settable(l, -3);
};
lua_newtable(l);
if (start) {
MdnsService.QueryServers(callback);
}
return 1;
}
enum GameResults {
GameNoResult,
GameVictory,
GameDefeat,
GameDraw,
GameQuitToMenu,
GameRestart,
};
enum RevealTypes {
cNoRevelation,
cAllUnits,
cBuildingsOnly
};
enum NetGameTypes {
SettingsSinglePlayerGame,
SettingsMultiPlayerGame,
Unset
};
class Settings {
NetGameTypes NetGameType;
SettingsPresets Presets[PlayerMax];
int Resources;
int NumUnits;
int Opponents;
int Difficulty;
GameTypes GameType;
FieldOfViewTypes FoV;
MapRevealModes RevealMap;
RevealTypes DefeatReveal;
bool NoFogOfWar;
bool Inside;
bool AiExplores;
bool SimplifiedAutoTargeting;
int _Bitfield @ Flags;
bool GetUserGameSetting(int i);
void SetUserGameSetting(int i, bool v);
};
enum MapRevealModes {
cHidden,
cKnown,
cExplored,
cNumOfModes
};
enum FieldOfViewTypes {
cShadowCasting,
cSimpleRadial,
NumOfTypes
};
enum GameTypes {
SettingsGameTypeMapDefault = SettingsPresetMapDefault,
SettingsGameTypeMelee = 0,
SettingsGameTypeFreeForAll,
SettingsGameTypeTopVsBottom,
SettingsGameTypeLeftVsRight,
SettingsGameTypeManVsMachine,
SettingsGameTypeManTeamVsMachine,
SettingsGameTypeMachineVsMachine,
SettingsGameTypeMachineVsMachineTraining,
};
/// Attack with force at position
/// Attack with force
class CVideo
{
public:
int Width;
int Height;
int Depth;
bool FullScreen;
bool ResizeScreen(int width, int height);
};
class CGraphic
{
public:
static CGraphic *New(const std::string file, int w = 0, int h = 0);
static CGraphic *ForceNew(const std::string file, int w = 0, int h = 0);
static CGraphic *Get(const std::string file);
static void Free(CGraphic *);
void Load(bool grayscale = false);
void Resize(int w, int h);
void SetPaletteColor(int idx, int r, int g, int b);
void OverlayGraphic(CGraphic *g, bool mask = false);
};
class CPlayerColorGraphic : public CGraphic
{
public:
static CPlayerColorGraphic *New(const std::string file, int w = 0, int h = 0);
static CPlayerColorGraphic *ForceNew(const std::string file, int w = 0, int h = 0);
static CPlayerColorGraphic *Get(const std::string file);
};
class CColor {
CColor(unsigned char r = 0, unsigned char g = 0, unsigned char b = 0,
unsigned char a = 0);
unsigned char R;
unsigned char G;
unsigned char B;
unsigned char A;
};
class CUnitType
{
std::string Ident;
std::string Name;
tolua_readonly int Slot;
int MinAttackRange;
int ClicksToExplode;
int GivesResource;
int TileWidth;
int TileHeight;
};
class CFont
{
static CFont *New(const std::string ident, CGraphic *g);
static CFont *Get(const std::string ident);
int Height();
int Width(const std::string text);
};
class CFontColor
{
static CFontColor *New(const std::string ident);
static CFontColor *Get(const std::string ident);
SDL_Color Colors[MaxFontColors];
};
enum EditorRunningType {
EditorNotRunning = 0, /// Not Running
EditorStarted = 1, /// Editor Enabled at all
EditorCommandLine = 2, /// Called from Command Line
EditorEditing = 4, /// Editor is fully running
};
class CEditor
{
vector<string> UnitTypes;
bool TerrainEditable;
const CUnitType *StartUnit;
bool WriteCompressedMaps;
EditorRunningType Running;
void CreateRandomMap(bool shuffleTranslitions) const;
};
class CMapInfo
{
string Description;
string Filename;
string Preamble;
string Postamble;
int MapWidth;
int MapHeight;
PlayerTypes PlayerType[PlayerMax];
};
class CTileset
{
string Name;
};
class CMap
{
CMapInfo Info;
CTileset *Tileset;
};
class CMinimap
{
int X;
int Y;
int W;
int H;
bool WithTerrain;
bool ShowSelected;
bool Transparent;
};
class ServerSetupStateRacesArray {
int& operator[](int idx) { return p[idx].Race; }
int& operator[](int idx) const { return p[idx].Race; }
};
enum SlotOption {
Available @ SlotAvailable,
Computer @ SlotComputer,
Closed @ SlotClosed,
};
class CServerSetup {
Settings ServerGameSettings;
SlotOption CompOpt[PlayerMax];
unsigned short Ready[PlayerMax]; // cannot use char since tolua interpret variable as string.
tolua_property unsigned char ResourcesOption;
tolua_property unsigned char UnitsOption;
tolua_property unsigned char FogOfWar;
tolua_property unsigned char Inside;
tolua_property unsigned char RevealMap;
tolua_property unsigned char GameTypeOption;
tolua_property unsigned char Difficulty;
tolua_property unsigned char Opponents;
tolua_property tolua_readonly ServerSetupStateRacesArray *Race;
};
class GraphicAnimation
{
GraphicAnimation(CGraphic *g, int ticksPerFrame);
virtual GraphicAnimation * clone();
};
class CParticle
{
virtual CParticle* clone();
void setDrawLevel(int value);
};
class StaticParticle : public CParticle
{
public:
StaticParticle(CPosition position, GraphicAnimation *animation, int drawlevel = 0);
};
class CChunkParticle : public CParticle
{
public:
CChunkParticle(CPosition position, GraphicAnimation *smokeAnimation, GraphicAnimation *debrisAnimation, GraphicAnimation *destroyAnimation, int minVelocity = 0, int maxVelocity = 400, int minTrajectoryAngle = 77, int maxTTL = 0, int drawlevel = 0);
int getSmokeDrawLevel() const;
int getDestroyDrawLevel() const;
void setSmokeDrawLevel(int value);
void setDestroyDrawLevel(int value);
};
class CSmokeParticle : public CParticle
{
public:
CSmokeParticle(CPosition position, GraphicAnimation *animation, float speedx = 0, float speedy = -22.0, int drawlevel = 0);
};
class CRadialParticle : public CParticle
{
public:
CRadialParticle(CPosition position, GraphicAnimation *smokeAnimation, int maxSpeed, int drawlevel = 0);
};
class CParticleManager
{
public:
CParticleManager();
~CParticleManager();
void add(CParticle *particle);
};
enum PlayerTypes {
PlayerNeutral = 2,
PlayerNobody = 3,
PlayerComputer = 4,
PlayerPerson = 5,
PlayerRescuePassive = 6,
PlayerRescueActive = 7,
};
class CPlayer
{
int Index;
string Name;
PlayerTypes Type;
int Race;
string AiName;
Vec2i StartPos;
void SetStartView(const Vec2i &pos);
int Resources[MaxCosts];
int StoredResources[MaxCosts];
int Incomes[MaxCosts];
const int Revenue[MaxCosts];
const int UnitTypesCount[UnitTypeMax];
const int UnitTypesAiActiveCount[UnitTypeMax];
bool AiEnabled;
int NumBuildings;
int Supply;
int Demand;
int UnitLimit;
int BuildingLimit;
int TotalUnitLimit;
int Score;
int TotalUnits;
int TotalBuildings;
int TotalResources[MaxCosts];
int TotalRazings;
int TotalKills;
int SpeedResourcesHarvest[MaxCosts];
int SpeedResourcesReturn[MaxCosts];
int SpeedBuild;
int SpeedTrain;
int SpeedUpgrade;
int SpeedResearch;
CUnit& GetUnit(int index) const;
int GetUnitCount() const;
bool IsEnemy(const CPlayer &player) const;
bool IsEnemy(const CUnit &unit) const;
bool IsAllied(const CPlayer &player) const;
bool IsAllied(const CUnit &unit) const;
bool HasSharedVisionWith(const CPlayer &player) const;
bool IsTeamed(const CPlayer &player) const;
bool IsTeamed(const CUnit &unit) const;
};
class CUpgrade
{
static CUpgrade *New(const std::string ident);
static CUpgrade *Get(const std::string ident);
std::string Name;
int Costs[MaxCosts];
CIcon *Icon;
};
class Vec2i
{
short int x;
short int y;
};
class CUnit
{
tolua_readonly Vec2i tilePos;
tolua_readonly CUnitType *Type;
tolua_readonly CPlayer *Player;
CUnit *Goal;
bool Active;
int ResourcesHeld;
};
class CPreference
{
bool ShowSightRange;
bool ShowReactionRange;
bool ShowAttackRange;
bool ShowMessages;
bool ShowNoSelectionStats;
bool BigScreen;
bool PauseOnLeave;
tolua_property bool AiExplores;
bool GrayscaleIcons;
bool IconsShift;
bool StereoSound;
bool MineNotifications;
bool DeselectInMine;
bool NoStatusLineTooltips;
tolua_property bool SimplifiedAutoTargeting;
tolua_property bool AiChecksDependencies;
bool HardwareCursor;
bool SelectionRectangleIndicatesDamage;
unsigned int FrameSkip;
unsigned int ShowOrders;
unsigned int ShowNameDelay;
unsigned int ShowNameTime;
unsigned int AutosaveMinutes;
CGraphic *IconFrameG;
CGraphic *PressedIconFrameG;
};
class CUnitManager
{
CUnit &GetSlotUnit(int index) const;
};
enum ViewportModeType {
VIEWPORT_SINGLE = 0,
VIEWPORT_SPLIT_HORIZ,
VIEWPORT_SPLIT_HORIZ3,
VIEWPORT_SPLIT_VERT,
VIEWPORT_QUAD
};
class LuaActionListener
{
LuaActionListener(lua_State *lua, lua_Object luaref);
};
class CUIButton
{
CUIButton();
int X;
int Y;
string Text;
ButtonStyle *Style;
LuaActionListener *Callback;
};
class CMapArea
{
int X;
int Y;
int EndX;
int EndY;
int ScrollPaddingLeft;
int ScrollPaddingRight;
int ScrollPaddingTop;
int ScrollPaddingBottom;
};
class CViewport
{
};
class CFiller
{
CFiller();
CGraphic *G;
int X;
int Y;
};
class vector
{
TOLUA_TEMPLATE_BIND(T, CFiller, CUIButton, CUIUserButton, string)
vector();
~vector();
const T& operator[](int index) const;
T& operator[](int index);
const T& at(int index) const;
T& at(int index);
const T& front() const;
T& front();
const T& back() const;
T& back();
void push_back(T val);
void pop_back();
void assign(int num, const T& val);
void clear();
bool empty() const;
int size() const;
};
class CButtonPanel
{
int X;
int Y;
vector<CUIButton> Buttons;
CColor AutoCastBorderColorRGB;
bool ShowCommandKey;
};
class CPieMenu
{
CGraphic *G;
int MouseButton;
int X[8];
int Y[8];
void SetRadius(int radius);
};
class CResourceInfo
{
CGraphic *G;
int IconFrame;
int IconX;
int IconY;
int IconWidth;
int TextX;
int TextY;
};
class CInfoPanel
{
CGraphic *G;
int X;
int Y;
};
class CUIUserButton
{
CUIUserButton();
bool Clicked;
CUIButton Button;
};
class CStatusLine
{
void Set(const std::string status);
const std::string &Get();
void Clear();
int Width;
int TextX;
int TextY;
CFont *Font;
};
class CUITimer
{
int X;
int Y;
CFont *Font;
};
class CUserInterface
{
string NormalFontColor;
string ReverseFontColor;
vector<CFiller> Fillers;
CResourceInfo Resources[MaxResourceInfo];
CInfoPanel InfoPanel;
string DefaultUnitPortrait;
CUIButton *SingleSelectedButton;
vector<CUIButton> SelectedButtons;
CFont *MaxSelectedFont;
int MaxSelectedTextX;
int MaxSelectedTextY;
CUIButton *SingleTrainingButton;
vector<CUIButton> TrainingButtons;
CUIButton *UpgradingButton;
CUIButton *ResearchingButton;
vector<CUIButton> TransportingButtons;
vector<string> LifeBarColorNames;
vector<int> LifeBarPercents;
int LifeBarYOffset;
int LifeBarPadding;
bool LifeBarBorder;
CColor CompletedBarColorRGB;
bool CompletedBarShadow;
CButtonPanel ButtonPanel;
CPieMenu PieMenu;
CViewport *MouseViewport;
CMapArea MapArea;
CFont *MessageFont;
int MessageScrollSpeed;
CUIButton MenuButton;
CUIButton NetworkMenuButton;
CUIButton NetworkDiplomacyButton;
vector<CUIUserButton> UserButtons;
CMinimap Minimap;
CStatusLine StatusLine;
CUITimer Timer;
Vec2i EditorSettingsAreaTopLeft;
Vec2i EditorSettingsAreaBottomRight;
Vec2i EditorButtonAreaTopLeft;
Vec2i EditorButtonAreaBottomRight;
void Load();
};
class CIcon
{
static CIcon *New(const std::string ident);
static CIcon *Get(const std::string ident);
tolua_readonly tolua_property__s std::string Ident;
CPlayerColorGraphic *G;
int Frame;
void ClearExtraGraphics();
void AddSingleSelectionGraphic(CPlayerColorGraphic *g);
void AddGroupSelectionGraphic(CPlayerColorGraphic *g);
void AddContainedGraphic(CPlayerColorGraphic *g);
};
class Color
{
Color(int r, int g, int b, int a = 255);
int r;
int g;
int b;
int a;
};
class Graphics
{
enum {
LEFT = 0,
CENTER,
RIGHT
};
class Widget
{
virtual void setWidth(int width);
virtual int getWidth() const;
virtual void setHeight(int height);
virtual int getHeight() const;
virtual void setSize(int width, int height);
virtual void setX(int x);
virtual int getX() const;
virtual void setY(int y);
virtual int getY() const;
virtual void setPosition(int x, int y);
virtual void setBorderSize(int width);
virtual unsigned int getBorderSize() const;
virtual void setEnabled(bool enabled);
virtual bool isEnabled() const;
virtual void setVisible(bool visible);
virtual bool isVisible() const;
virtual void setDirty(bool isDirty);
virtual void setBaseColor(const Color color);
virtual const Color &getBaseColor() const;
virtual void setForegroundColor(const Color color);
virtual const Color &getForegroundColor() const;
virtual void setBackgroundColor(const Color color);
virtual const Color &getBackgroundColor() const;
virtual void setDisabledColor(const Color color);
virtual const Color &getDisabledColor() const;
static void setGlobalFont(CFont *font);
virtual void setForegroundColor(const Color color);
virtual void setBackgroundColor(const Color color);
virtual void setBaseColor(const Color color);
virtual void setSize(int width, int height);
virtual void setBorderSize(int width);
virtual void setFont(CFont *font);
virtual int getHotKey() const;
virtual void setHotKey(const int key);
virtual void setHotKey(const char *key);
virtual void requestFocus();
virtual void addActionListener(LuaActionListener *actionListener);
virtual void addMouseListener(LuaActionListener *actionListener);
virtual void addKeyListener(LuaActionListener *actionListener);
};
class BasicContainer : public Widget
{
};
class ScrollArea : public BasicContainer
{
ScrollArea();
virtual void setContent(Widget *widget);
virtual Widget *getContent();
virtual void setScrollbarWidth(int width);
virtual int getScrollbarWidth();
virtual void scrollToBottom();
virtual void scrollToTop();
};
class ImageWidget : public Widget
{
ImageWidget(CGraphic *image);
ImageWidget(Mng *image);
ImageWidget(Movie *image);
};
class Button : public Widget
{
};
class ButtonWidget : public Button
{
ButtonWidget(const std::string caption);
virtual void setCaption(const std::string caption);
virtual const std::string &getCaption() const;
virtual void adjustSize();
};
class ImageButton : public Button
{
ImageButton();
ImageButton(const std::string caption);
void setNormalImage(CGraphic *image);
void setPressedImage(CGraphic *image);
void setDisabledImage(CGraphic *image);
};
class RadioButton : public Widget
{
RadioButton();
RadioButton(const std::string caption, const std::string group, bool marked = false);
virtual bool isMarked();
virtual void setMarked(bool marked);
virtual const std::string &getCaption() const;
virtual void setCaption(const std::string caption);
virtual void setGroup(const std::string group);
virtual const std::string &getGroup() const;
virtual void adjustSize();
};
class ImageRadioButton : public RadioButton
{
ImageRadioButton();
ImageRadioButton(const std::string caption, const std::string group, bool marked = false);
void setUncheckedNormalImage(CGraphic *image);
void setUncheckedPressedImage(CGraphic *image);
void setUncheckedDisabledImage(CGraphic *image);
void setCheckedNormalImage(CGraphic *image);
void setCheckedPressedImage(CGraphic *image);
void setCheckedDisabledImage(CGraphic *image);
};
class CheckBox : public Widget
{
CheckBox();
CheckBox(const std::string caption, bool marked = false);
virtual bool isMarked() const;
virtual void setMarked(bool marked);
virtual const std::string &getCaption() const;
virtual void setCaption(const std::string caption);
virtual void adjustSize();
};
class ImageCheckBox : public CheckBox
{
ImageCheckBox();
ImageCheckBox(const std::string caption, bool marked = false);
void setUncheckedNormalImage(CGraphic *image);
void setUncheckedPressedImage(CGraphic *image);
void setUncheckedDisabledImage(CGraphic *image);
void setCheckedNormalImage(CGraphic *image);
void setCheckedPressedImage(CGraphic *image);
void setCheckedDisabledImage(CGraphic *image);
};
class Slider : public Widget
{
Slider(double scaleEnd = 1.0);
Slider(double scaleStart, double scaleEnd);
virtual void setScale(double scaleStart, double scaleEnd);
virtual double getScaleStart() const;
virtual void setScaleStart(double scaleStart);
virtual double getScaleEnd() const;
virtual void setScaleEnd(double scaleEnd);
virtual double getValue();
virtual void setValue(double value);
virtual void setMarkerLength(int length);
virtual int getMarkerLength() const;
virtual void setOrientation(unsigned int orientation);
virtual unsigned int getOrientation() const;
virtual void setStepLength(double length);
virtual double getStepLength() const;
enum { HORIZONTAL = 0, VERTICAL };
};
class ImageSlider : public Slider
{
ImageSlider(double scaleEnd = 1.0);
ImageSlider(double scaleStart, double scaleEnd);
void setMarkerImage(CGraphic *image);
void setBackgroundImage(CGraphic *image);
void setDisabledBackgroundImage(CGraphic *image);
};
class Label : public Widget
{
Label(const std::string caption);
const std::string &getCaption() const;
void setCaption(const std::string caption);
virtual void setAlignment(unsigned int alignment);
virtual unsigned int getAlignment();
virtual void adjustSize();
};
class MultiLineLabel : public Widget
{
MultiLineLabel();
MultiLineLabel(const std::string caption);
virtual void setCaption(const std::string caption);
virtual const std::string &getCaption() const;
virtual void setAlignment(unsigned int alignment);
virtual unsigned int getAlignment();
virtual void setVerticalAlignment(unsigned int alignment);
virtual unsigned int getVerticalAlignment();
virtual void setLineWidth(int width);
virtual int getLineWidth();
virtual void adjustSize();
virtual void draw(gcn::Graphics *graphics);
enum {
LEFT = 0,
CENTER,
RIGHT,
TOP,
BOTTOM
};
class TextBox : public Widget
{
TextBox(const std::string text);
virtual void setEditable(bool editable);
virtual std::string getText();
};
class TextField : public Widget
{
TextField(const std::string text);
virtual void setText(const std::string text);
virtual std::string &getText();
virtual void setPassword(bool flag);
};
class ImageTextField : public Widget
{
ImageTextField(const std::string text);
virtual void setText(const std::string text);
virtual std::string &getText();
void setItemImage(CGraphic *image);
virtual void setPassword(bool flag);
};
class ListBox : public Widget
{
};
class ImageListBox : public ListBox
{
};
class ListBoxWidget : public ScrollArea
{
ListBoxWidget(unsigned int width, unsigned int height);
void setList(lua_State *lua, lua_Object *lo);
void setSelected (int selected);
int getSelected();
};
class ImageListBoxWidget : public ListBoxWidget
{
ImageListBoxWidget(unsigned int width, unsigned int height);
void setList(lua_State *lua, lua_Object *lo);
void setSelected (int selected);
int getSelected();
void setItemImage(CGraphic *image);
void setUpButtonImage(CGraphic *image);
void setUpPressedButtonImage(CGraphic *image);
void setDownButtonImage(CGraphic *image);
void setDownPressedButtonImage(CGraphic *image);
void setLeftButtonImage(CGraphic *image);
void setLeftPressedButtonImage(CGraphic *image);
void setRightButtonImage(CGraphic *image);
void setRightPressedButtonImage(CGraphic *image);
void setHBarImage(CGraphic *image);
void setVBarImage(CGraphic *image);
void setMarkerImage(CGraphic *image);
};
class Window : public BasicContainer
{
Window();
Window(const std::string caption);
Window(Widget *content, const std::string caption = "");
virtual void setCaption(const std::string caption);
virtual const std::string &getCaption() const;
virtual void setAlignment(unsigned int alignment);
virtual unsigned int getAlignment() const;
virtual void setContent(Widget* widget);
virtual Widget* getContent() const;
virtual void setPadding(unsigned int padding);
virtual unsigned int getPadding() const;
virtual void setTitleBarHeight(unsigned int height);
virtual unsigned int getTitleBarHeight();
virtual void setMovable(bool movable);
virtual bool isMovable() const;
virtual void resizeToContent();
virtual void setOpaque(bool opaque);
virtual bool isOpaque();
};
class Windows : public Window
{
Windows(const std::string text, int width, int height);
void add(Widget *widget, int x, int y);
};
class ScrollingWidget : public ScrollArea
{
ScrollingWidget(int width, int height);
void add(Widget *widget, int x, int y);
void restart();
void setSpeed(float speed);
float getSpeed();
};
class DropDown : public BasicContainer
{
virtual int getSelected();
virtual void setSelected(int selected);
virtual void setScrollArea(ScrollArea* scrollArea);
virtual ScrollArea *getScrollArea();
virtual void setListBox(ListBox* listBox);
virtual ListBox *getListBox();
};
class DropDownWidget : public DropDown
{
DropDownWidget();
void setList(lua_State *lua, lua_Object *lo);
virtual ListBox *getListBox();
virtual void setSize(int width, int height);
};
class ImageDropDownWidget : public DropDown
{
ImageDropDownWidget();
void setList(lua_State *lua, lua_Object *lo);
virtual ListBox *getListBox();
virtual void setSize(int width, int height);
void setItemImage(CGraphic *image);
void setDownNormalImage(CGraphic *image);
void setDownPressedImage(CGraphic *image);
};
class StatBoxWidget : public Widget
{
StatBoxWidget(int width, int height);
void setCaption(const std::string s);
const std::string &getCaption() const;
void setPercent(const int percent);
int getPercent() const;
};
class Container : public BasicContainer
{
Container();
virtual void setOpaque(bool opaque);
virtual bool isOpaque() const;
virtual void add(Widget *widget, int x, int y);
virtual void remove(Widget *widget);
virtual void clear();
};
class MenuScreen : public Container
{
MenuScreen();
int run(bool loop = true);
void stop(int result = 0);
void stopAll(int result = 0);
void addLogicCallback(LuaActionListener *actionListener);
void setDrawMenusUnder(bool drawunder);
bool getDrawMenusUnder();
};